Re: Bug in wxPython? MessageDialog.ShowModal() returning always zero on OS X
Jari Nevala <[email protected]>
| Newsgroups | gmane.comp.python.wxpython.devel |
|---|---|
| Message-ID | <[email protected]> |
Thanks for the answer again.
Im a bit surprised how much code this workaround requires. After all, were
talking about a simple prompt dialog which should return the result
correctly, even when calling it from a separate thread (just like it works
on Windows).
Is this known issue going to be fixed in the upcoming wxPython release?
Anyway, I tried to address this with pubsub. It doesnt seem to work, the
answer is always None so the while loop doesnt exit.
The code:
import threading,wximport timefrom wx.lib.pubsub import pub
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
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...")
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()
pub.sendMessage('dialog.response', response=result)
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()
lauantai 16. toukokuuta 2015 17.44.00 UTC+3 kevino kirjoitti:
>
> On May 16, 2015, at 6:49 AM, Jari Nevala <[email protected] <javascript:>>
> 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 <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] <javascript:>.
> 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.