Re: Bug in wxPython? MessageDialog.ShowModal() returning always zero on OS X
Kevin Ollivier <[email protected]>
| Newsgroups | gmane.comp.python.wxpython.devel |
|---|---|
| Message-ID | <[email protected]> |
On May 16, 2015, at 6:49 AM, Jari Nevala <[email protected]> wrote: > Thanks for the answers. As I am new to wxPython. I looked at the CallAfter(). It seemst work as expected. But I need to switch code in my thread based on the dialog result. How can I do that? For this particular code, since the very first thing you do is show the dialog, I would say to just show the dialog, get the result, and start the thread, passing in the result. For the more general case where you need to show a prompt or otherwise get user input for a thread while it's in progress, though, a good way to do things is to use pubsub. Some basic docs are here: http://wiki.wxpython.org/WxLibPubSub For this case, to wait on the message to arrive inside the thread, you would do something like this (pseudocode, untested...): import time from wx.lib.pubsub import pub # Your MyFrame class code... def ShowDialog(self, msg): # code from your example goes here pub.sendMessage('dialog.response', response=result) def __run(self): # do stuff.... answer = None def _onDialogResponse(response): answer = response pub.subscribe(onDialogResponse, 'dialog.response') wx.CallAfter(self.ShowDialog, "Do you like SPAM?") while answer is None: time.sleep(0.1) pub.unsubscribe(onDialogResponse, 'dialog.response') # so we don't get a response when something else calls the dialog print("Answer is %r" % answer) print("Do stuff with answer here...") Regards, Kevin > Here is some code (I modified the CallAfter() example found at http://wiki.wxpython.org/CallAfter a bit): > > import threading,wx > > ID_RUN=101 > ID_RUN2=102 > > class MyFrame(wx.Frame): > def __init__(self, parent, ID, title): > wx.Frame.__init__(self, parent, ID, title) > panel = wx.Panel(self, -1) > mainSizer=wx.BoxSizer(wx.HORIZONTAL) > mainSizer.Add(wx.Button(panel, ID_RUN, "Button 1")) > mainSizer.Add(wx.Button(panel, ID_RUN2, "Button 2")) > panel.SetSizer(mainSizer) > mainSizer.Fit(self) > wx.EVT_BUTTON(self, ID_RUN, self.onClick1) > wx.EVT_BUTTON(self, ID_RUN2, self.onClick2) > > def onClick1(self,event): > print "Clicked button 1" > wx.CallAfter(self.ShowDialog, "I don't appear until after onClick1 exits") > s=raw_input("Enter something:") > print s > > def onClick2(self,event): > print "Clicked button 2" > t=threading.Thread(target=self.__run) > t.start() > #how to use message dialog result here? > > def __run(self): > wx.CallAfter(self.ShowDialog, "I appear immediately (event handler\nexited when onClick2 finished)") > s=raw_input("Enter something in this thread:") > print s > > def ShowDialog(self,msg): > dlg=wx.MessageDialog(self, msg, "Called after", wx.YES_NO|wx.ICON_INFORMATION) > result = dlg.ShowModal() > #how to pass result to calling funtion? > dlg.Destroy() > > > class MyApp(wx.App): > def OnInit(self): > frame = MyFrame(None, -1, "CallAfter demo") > frame.Show(True) > frame.Centre() > return True > > app = MyApp(0) > app.MainLoop() > > keskiviikko 13. toukokuuta 2015 18.49.58 UTC+3 kevino kirjoitti: > > On May 13, 2015, at 8:21 AM, Robin Dunn <[email protected]> wrote: > > > Jari Nevala wrote: > >> Hi, > >> > >> I noticed recently that when a MessageDialog is created in a thread and > >> its ShowModal() is called, it always returns 0 on OS X. This is an > >> error, because it should return the wx.ID of the button pressed. On > >> Windows this does not happen. > >> > >> When the MessageDialog is created in the main thread, the ShowModal() > >> returns correct value on OS X and PC. > >> > >> The Mac I used to reproduce this problem is Macbook Air with OS X > >> version 10.9.5. wxPython version is 3.0.2.0. My PC is running Windowsx > >> 8.1 and also has wxPython 3.0.2.0 installed. > >> > >> Below is code to reproduce the problem. See the comments. > >> Code also available in pastebin: http://pastebin.com/QbNkw5gz > >> > >> So is this a bug in wxPython? > > > > It's a known issue, but it only happens with stock dialogs shown before the MainLoop starts. So the easy fix is to just move that code to a method and use wx.CallAfter or wx.CallLater in OnInit to invoke it right after the MainLoop starts processing events. > > Also, it's important to note that Cocoa, and GUI libraries in general, are not thread-safe. On Mac there is a further restriction that the GUI must be started from the app's main thread. So the best practice is that you start the main loop in the main thread, and any time you want to call GUI code from a thread, as you do in the testThread method, you need to use wx.CallAfter or wx.CallLater to run the GUI code to ensure it runs in the main thread. > > Regards, > > Kevin > > > -- > > Robin Dunn > > Software Craftsman > > http://wxPython.org > > > > -- > > You received this message because you are subscribed to the Google Groups "wxPython-dev" group. > > To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. > > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google Groups "wxPython-dev" group. > To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "wxPython-dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.