Search code examples
pythoneventswxpython

How to properly implement event for button click and how to change GUI elements on the fly


I made a small ugly GUI, following some tutorials and reading what I understood on basic WxPython I am working on python 2.6 currently. I managed to get most things to display but I want to basically get the filepath on the filepicker button when I click on the check button but when I attempted to make the bind I get an error saying the object does not have the attribute.

It is more of a basic python issue than Wxpython itself in my opinion I don't know how it wants me to perform the call for the event

Also I would like to eventually change the passed text to green or something or an event but if I try to do anything outside of basicGUI with the elements I fail to properly reference them(things like the panel, etc) so any ideas on how to implement changes to GUI elements would be helpful on top of the button event.

I tried copying an example of someone else using the button event, but it does not work in my implementation because the way I defined the class I think... I need to figure out how to adapt that line of code so it references the object properly.

import wx
import ctypes
try:
    ctypes.windll.shcore.SetProcessDpiAwareness(True)
except:
    pass


class windowClass(wx.Frame):

    def __init__(self,*args,**kwargs):

        super(windowClass,self).__init__(*args,**kwargs)

        self.basicGUI()

    #GUI elements    
    def basicGUI(self):
        panel=wx.Panel(self)
        menu_bar=wx.MenuBar()
        box_sizer=wx.BoxSizer()
        box_sizer.Add(panel, 1, wx.ALL | wx.EXPAND) 

        button_text=wx.StaticText(panel, label="Select a file")
        file_button=wx.FilePickerCtrl(panel)
        check_button=wx.Button(panel, label='Check')

        #self.Bind(wx.EVT_BUTTON, OnCheckButton(self), check_button)

        a_text=wx.StaticText(panel, label="a file status")
        b_text=wx.StaticText(panel, label="b file status")
        c_text=wx.StaticText(panel, label="c file status")
        passed_text=wx.StaticText(panel, label="passed")

        #set items on the grid
        sizer = wx.GridBagSizer(5, 5)
        sizer.Add(button_text, (0, 0))
        sizer.Add(file_button, (0, 2))
        sizer.Add(check_button,(1, 2))
        sizer.Add(a_text,    (2, 0))
        sizer.Add(b_text,    (3, 0))
        sizer.Add(c_text,    (4, 0))
        sizer.Add(passed_text, (2, 1))

        #make border
        border = wx.BoxSizer()
        border.Add(sizer, 1, wx.ALL | wx.EXPAND, 5)
        #use sizers
        panel.SetSizerAndFit(border)  
        self.SetSizerAndFit(box_sizer)  
        #show GUI
        self.SetTitle('file check')
        self.Centre()
        self.Show(True)

        def OnCheckButton(self,event):
            print("perform check")   #debug line
            #file_button.GetPath(self)  this probably won't work either as is, 
            #don't know how to pass the button info

app=wx.App()

windowClass(None)

print("passed")

app.MainLoop()

at this early stage I expect to click the button and be able to print or do other things... but since it says it is not defined it is sort of an odd error.

self.Bind(wx.EVT_BUTTON, self.OnCheckButton(self), check_button)
AttributeError: 'windowClass' object has no attribute 'OnCheckButton'

Solution

  • First: you have wrong indentations and OnCheckButton is not method in class windowClass but normal function inside basicGUI so it can't find method OnCheckButton in class windowClass and you get error 'windowClass' object has no attribute 'OnCheckButton'

    Second: probably in all GUI frameworks (probably in all languages) Button needs "callback" - it means function's name without () and arguments. When you click button then system will run this function by adding ()

    self.Bind(wx.EVT_BUTTON, self.OnCheckButton, check_button)
    

    Third: use self. in self.file_button to have access to this variable in metehod OnCheckButton and get path of selected file.


    Full code:

    import wx
    import ctypes
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(True)
    except:
        pass
    
    
    class WindowClass(wx.Frame):
    
        def __init__(self, *args, **kwargs):
            super(WindowClass,self).__init__(*args, **kwargs)
            self.basicGUI()
    
        #GUI elements    
        def basicGUI(self):
            panel = wx.Panel(self)
            menu_bar = wx.MenuBar()
            box_sizer = wx.BoxSizer()
            box_sizer.Add(panel, 1, wx.ALL|wx.EXPAND) 
    
            button_text = wx.StaticText(panel, label="Select a .cpf file")
            self.file_button = wx.FilePickerCtrl(panel)
            check_button = wx.Button(panel, label='Check')
    
            self.Bind(wx.EVT_BUTTON, self.OnCheckButton, check_button)
    
            a_text = wx.StaticText(panel, label="a file status")
            b_text = wx.StaticText(panel, label="b file status")
            c_text = wx.StaticText(panel, label="c file status")
            passed_text = wx.StaticText(panel, label="passed")
    
            #set items on the grid
            sizer = wx.GridBagSizer(5, 5)
            sizer.Add(button_text, (0, 0))
            sizer.Add(self.file_button, (0, 2))
            sizer.Add(check_button,(1, 2))
            sizer.Add(a_text, (2, 0))
            sizer.Add(b_text, (3, 0))
            sizer.Add(c_text, (4, 0))
            sizer.Add(passed_text, (2, 1))
    
            #make border
            border = wx.BoxSizer()
            border.Add(sizer, 1, wx.ALL|wx.EXPAND, 5)
            #use sizers
            panel.SetSizerAndFit(border)  
            self.SetSizerAndFit(box_sizer)  
            #show GUI
            self.SetTitle('file check')
            self.Centre()
            self.Show(True)
    
        # indentations are very important in Python
        def OnCheckButton(self, event): 
            print("perform check")   #debug line
            print(self.file_button.GetPath())
    
    app = wx.App()
    WindowClass(None)
    print("passed")
    app.MainLoop()
    

    BTW: read PEP 8 -- Style Guide for Python Code. It suggests how to format code in Python and many people and tools respect these rules.