Re: Gnome "Quit" menu is like clicking a button in a wxPython modal dialog
Matthias Brennwald <[email protected]> Sun, 13 Dec 2020 22:59:07 +0100
| Newsgroups | gmane.comp.python.wxpython |
|---|---|
| Message-ID | <[email protected]> |
On Sun, Dec 13, 2020 at 17:05, Dietmar Schwertberger <[email protected]> wrote: > A working minimal code sample is always a good idea. Your previous > sample was too minimal. Alright, I took the code of my real-world application and stripped it down in order to better illustrate my situation (see the attached demo). I am still a noob when it comes to catching and handling events, so it would be great if someone could guide me to fix this demo code such that it behaves as intended (see below). My demo program consists of three sequential steps (mostly implemended as mockups, without any real functionality): A. Configuration: load some configuration parameters from a file, then connect to a measurement instrument, and check if the measurement instrument is alright. Then the program shows Show a MessageDialog saying B. Warmup: run a "warm up" procedure for the measurement instrument to make sure the instrument is ready to take good measurements. C. The user may now control the measurement in order to take measurements. Steps A and B are executed in separate threads in order to avoid blocking the GUI. At the end of (A) and (B), a MessageDialog is shown to inform the user about the progress, and to ask the user how to proceed. If you run the demo code, the Configuration step (thread of step A) will run for a few seconds and then the program will show a first MessageDialog to ask if the Warmup step (thread of step B) should run. This is a "yes/no" MessageDialog. If at this point the user hits the "Quit" menu, things go wrong: - The MessageDialog gets closed with a "yes" answer, and the program starts running the Warmup step (thread B), although the user did not give a "yes" or "no" answer. - The intended behaviour would be to keep the "yes/no" MessageDialog until the user answers the question by choosing either "yes" or "no". The wx.EVT_CLOSE event should be discarded. How can I get this to work as intended? -- You received this message because you are subscribed to the Google Groups "wxPython-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/wxpython-users/J2TALQ.ZUQEM7WRI7X91%40gmail.com.
demo
(text/x-python3, 4.5 KB)
#!/usr/bin/env python3
import wx
from threading import Thread
import time
class my_app(wx.App):
def __init__(self):
# wx.App init:
wx.App.__init__(self)
# Startup thread (load instrument config, connect to instrument):
self.startup_thread = startup_thread(self)
# Warmup thread (instrument warmup):
self.warmup_thread = warmup_thread(self)
# Main GUI frame:
self.frame_main = frame_main(self)
def startup(self):
# start running, load instrument configuration:
self.startup_thread.start()
def warmup(self):
# instrument warmup (ask user if warmup needed first):
dlg = wx.MessageDialog(self.frame_main, "The instrument has been configured successfully. Do you want to run the warmup procedure?", "Run Warmup?", wx.YES_NO | wx.ICON_QUESTION )
result = dlg.ShowModal()
dlg.Destroy()
if result == wx.ID_NO:
# user skipped warmup:
print('*** User skipped warmup!')
dlg=wx.MessageDialog(self.frame_main, "You skipped warmup, lets hope you know what you are doing!", "Be careful!", wx.OK|wx.ICON_WARNING)
dlg.ShowModal()
self.frame_main.enable_measurement()
else:
print('*** Starting warmup thread.')
self.warmup_thread.start()
def exit(self):
# stop all active threads and destroy frames:
self.startup_thread.stop()
self.warmup_thread.stop()
while self.startup_thread.is_active():
time.sleep(0.1)
while self.warmup_thread.is_active():
time.sleep(0.1)
wx.CallAfter(self.frame_main.Destroy)
###################################################################
class frame_main(wx.Frame):
def __init__(self, app):
wx.Frame.__init__(self, None, title="Instrument Control", size=(250,200), style=wx.DEFAULT_FRAME_STYLE)
self._app = app
self.Bind(wx.EVT_CLOSE, self.on_close_event)
# Add a button and stuff:
self.panel = wx.Panel(self, wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
self.button = wx.Button(self.panel, wx.ID_ANY, "Start measurement")
self.button.Disable() # start with the button disabled
sizer.Add(self.button, 0, wx.ALL, 4)
self.panel.SetSizer(sizer)
self.Layout()
self.Bind(wx.EVT_BUTTON, self.on_start_measurement, self.button)
self.Show()
def enable_measurement(self):
self._app.frame_main.button.Enable()
def on_start_measurement(self, event):
print('*** on_start_measurement')
def on_close_event(self, event):
print('*** on_close_event')
dlg = wx.MessageDialog(self, "Do you really want to close this application?", "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
result = dlg.ShowModal()
dlg.Destroy()
if result == wx.ID_OK:
self.exit()
def exit (self):
wx.CallAfter(self._app.exit)
###################################################################
# Startup thread:
class startup_thread(Thread):
# load instrument configuration, and set up instrument
def __init__(self, app):
Thread.__init__(self)
self._app = app
self._stop = False
self._active = False
def run(self):
self._active = True
msg = [ 'Loading instrument configuration from file...', 'Connecting to instrument...', 'Checking if instrument is alright...', 'Getting serial number...', 'Checking instrument status...' 'Turning on the instrument...' ]
for m in msg:
if self._stop:
break
print('Thread A: ' + m)
time.sleep(1)
if not self._stop:
print('Thread A: Instrument configuration completed!')
wx.CallAfter(self._app.warmup)
self._active = False
def stop(self):
if self._active:
print('*** Stopping startup_thread')
self._stop = True
def is_active(self):
return self._active
###################################################################
# Warmup thread:
class warmup_thread(Thread):
# instrument warmup
def __init__(self, app):
Thread.__init__(self)
self._app = app
self._stop = False
self._active = False
def run(self):
self._active = True
for k in range(10):
if self._stop:
break
print('Thread B: Instrument warming up...')
time.sleep(1)
if not self._stop:
print('Thread B: Instrument warmup done!')
wx.CallAfter(self._app.frame_main.enable_measurement)
self._active = False
def stop(self):
if self._active:
print('*** Stopping warmup thread')
self._stop = True
def is_active(self):
return self._active
###################################################################
# Main:
# Init the (wx)App:
app = my_app() # init the app
# Startup process:
app.startup() # start background thread to load instrument config, bring up instrument, and set up GUI accordingly
# Main event loop:
app.MainLoop()