Reputation: 3531
I want to execute a task when a Toggle Button is clicked(on) and toggle it off after the task is completed, I execute the task in a new process because I don't want it to block the UI, event.GetEventObject().SetValue(False)
seems to update correctly the value of the Toggle but it doesn't reflect on the UI.
from multiprocessing import Process
import time
import wx
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.toggle_button = wx.ToggleButton(self, wx.ID_ANY, "OK")
control = Control()
self.Bind(wx.EVT_TOGGLEBUTTON, control.action, self.toggle_button)
self.SetTitle("Update UI with a process")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.toggle_button, 0, 0, 0)
self.SetSizer(sizer)
self.Layout()
class Control():
def update_toggle(self, duration, event):
time.sleep(duration)
event.GetEventObject().SetValue(False)
print("Toggled")
def action(self, event):
if event.GetEventObject().GetValue():
self.update_toggle_process = Process(target = self.update_toggle,
args=(5, event,))
self.update_toggle_process.start()
else:
print("UnToggled")
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()
A call to event.GetEventObject().Update()
or event.GetEventObject().Refresh()
after changing the value of the Toggle doesn't seem to change anything.
EDIT:
If I use a Thread
instead of Process
, it works correctly, but I chose Process
over Thread
because I want the ability to kill it cleanly whenever I need to.
Python version: 3.7
WxPython version: 4.0.1
Upvotes: 3
Views: 276
Reputation: 2433
You must remember, that the your update_toggle runs in a new process. Simply put, it has got a copy of data, so if you call event.GetEventObject().SetValue(False) it happens in the new process, and the original one with the Window and Button won't know.
You must somehow pass a message from the new process to the original. I would suggest that the first thing you try is:
self.update_toggle_process.start()
self.update_toggle_process.join()
print("the process has finished")
This will block, but at least you will see if the "update_toggle_process" has finished and if this approach works. After that, there are a few possibilities:
Upvotes: 3