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.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.