Search code examples
pythonwxpythonpython-multiprocessing

How to enable/disable a button with wxPython in a multiprocessed function?


I'm trying to disable a button when I click on itand re-enable it once a function thats called with multiprocessing has finished.

Currently everytime I try to acess that button in the function it basically gives me a null reference.

class MyFrame(wx.Frame):

    def __init__(self):
        super().__init__(parent=None, title='Title', size=(800, 500), style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX)
        panel = wx.Panel(self)
        self.my_btn = wx.Button(panel, label='Label me')
        self.my_btn.Bind(wx.EVT_BUTTON,self.on_press)
        self.Show()


    def two(self):
        self.my_btn.Enable()

    def on_press(self, event):
        self.my_btn.Disable()
        Process(target=one).start()

def one():
    #something
    MyFrame.two(MyFrame)

I want that once one has finished the button to re-enable. But no matter what I try its either an TypeError or an AttributeError.


Solution

  • You must keep in mind that once you call Process(...).start(), you have 2 unrelated processes. They cannot just directly access one another's variables. So the possibility that is quite easy to understand would be:

    • In on_press do: self.process = Process(target=one); self.process.start()
    • Start a timer (wx.Timer) that periodically checks if the self.process is still running (self.process.is_alive())
    • Once the process is not alive any longer, you can enable the button.

    You may think it is suboptimal to "poll" the self.process, but it costs nearly nothing, and if you call it, like 20 times a second, the delay between the process end and the button re-enabling won't be noticable.

    Other option would be to start another thread and do self.process.join(). But remember, that you may not just call self.btn.Enable from a thread. Use wx.CallAfter. (generally speaking you can only call wx functions from the main thread).

    You can of course communicate between those 2 processes using pipes or queues, for example if you need to send results back.