OnInit does not return and app hangs

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

OnInit does not return and app hangs

Brendan Simon (eTRIX)
I am migrating an OS X app from wxPython 2.8.12.1 (Carbon) to wxPython 3.0.2.0 (Cocoa).

When OnInit completes, it returns True, but the calling function app.MainLoop() never seems to return.

I'm running the app from the command line (python2.7 myapp.py myargs), and I have to press ctrl-c to terminate the process.

This was not an issue with wxpy2.8.

Note the main windows are wx.ProgressDialog.  Other Frames can be instantiated and closed depending on the arguments passed to the app.  I think I remember (a long time ago) someone posting a solution that instantiated and frame and then destroyed in right away (or at the end) and that "fixed" things.  I tried that (from memory) but it made no difference.


Any ideas what the problem could be and how to resolve it?

Thanks, Brendan.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

wx.ProgressDialog not destroyed (was: OnInit does not return and app hangs)

Brendan Simon (eTRIX)
I've narrowed the issue down to wx.ProgressDialog.Update().

If I do:
    dlg = MyProgressDialog(title, message, maximum)
    dlg.Destroy()
    return True

then the MainLoop() exits as expected and python exits :)

If I do:
    dlg = MyProgressDialog(title, message, maximum)
    dlg.Update(0, new_message)
    dlg.Destroy()
    return True

then the MainLoop() never exits :(

Any ideas why this could be?

Thanks, Brendan.


On 17/06/2015 9:44 pm, Brendan Simon (eTRIX) wrote:
I am migrating an OS X app from wxPython 2.8.12.1 (Carbon) to wxPython 3.0.2.0 (Cocoa).

When OnInit completes, it returns True, but the calling function app.MainLoop() never seems to return.

I'm running the app from the command line (python2.7 myapp.py myargs), and I have to press ctrl-c to terminate the process.

This was not an issue with wxpy2.8.

Note the main windows are wx.ProgressDialog.  Other Frames can be instantiated and closed depending on the arguments passed to the app.  I think I remember (a long time ago) someone posting a solution that instantiated and frame and then destroyed in right away (or at the end) and that "fixed" things.  I tried that (from memory) but it made no difference.


Any ideas what the problem could be and how to resolve it?

Thanks, Brendan.


--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed

Brendan Simon (eTRIX)
On 18/06/2015 9:53 am, Brendan Simon (eTRIX) wrote:
I've narrowed the issue down to wx.ProgressDialog.Update().

If I do:
    dlg = MyProgressDialog(title, message, maximum)
    dlg.Destroy()
    return True

then the MainLoop() exits as expected and python exits :)

If I do:
    dlg = MyProgressDialog(title, message, maximum)
    dlg.Update(0, new_message)
    dlg.Destroy()
    return True

then the MainLoop() never exits :(

Any ideas why this could be?

Thanks, Brendan.


Here is a sample app.  Why does the program not exit properly?
Running python-2.7.10 (i386/x86_64 build), with wxPython 3.0.2.0 Cocoa, on OS X 10.9.5.

Thanks, Brendan.

import wx
#----------------------------------------------------------------------------
class MyProgressDialog(wx.ProgressDialog):
    """My Progress Dialog."""
    
    def __init__(self, *args, **kwargs):
        """Initialise class."""
        sty = 0
        sty |= wx.PD_APP_MODAL
        sty |= wx.PD_AUTO_HIDE
        #sty |= wx.PD_SMOOTH
        #sty |= wx.PD_CAN_ABORT
        #sty |= wx.PD_CAN_SKIP
        #sty |= wx.PD_LAPSED_TIMEE
        #sty |= wx.PD_ESTIMATED_TIME
        #sty |= wx.PD_REMAINING_TIME
        kwargs['style'] = kwargs.get('style', sty)
        wx.ProgressDialog.__init__(self, *args, **kwargs)
#----------------------------------------------------------------------------
class MyApp(wx.App):
    """My Application."""
    def __init__(self, argv):
        """Class constructor."""
        self.argv = argv
        wx.App.__init__(self, redirect=False)
    def OnInit(self):
        """OnInit() method."""
        tit = 'Test Title'
        msg = "This is a test message.  Please wait ..."
        max = 100
        dlg = MyProgressDialog(title=tit, message=msg, maximum=max)
         
        #dlg.Destroy()
        #return True

        (keepGoing, skip) = dlg.Update(50, "Half way there ...")
        wx.MilliSleep(1000)
         
        dlg.Destroy()
        return True
        
#----------------------------------------------------------------------------
def main_test():
    """Main test function."""
    
    app = MyApp("my arguments")
    print "DEBUG: MainLoop() starting."
    app.MainLoop()
    print "DEBUG: MainLoop() exited."
#----------------------------------------------------------------------------
if __name__ == "__main__":
    main_test()



--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed

Boštjan Mejak-4
What I would do is this:

with MyProgressDialog(title, message, maximum) as dlg:
    dlg.Update(0, new_message)

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed (was: OnInit does not return and app hangs)

Boštjan Mejak-4
In reply to this post by Brendan Simon (eTRIX)
What I would do is this:

with MyProgressDialog(title, message, maximum) as dlg:
    dlg.Update(0, new_message)

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed

Tim Roberts
In reply to this post by Brendan Simon (eTRIX)
Brendan Simon (eTRIX) wrote:
I've narrowed the issue down to wx.ProgressDialog.Update().

If I do:
    dlg = MyProgressDialog(title, message, maximum)
    dlg.Destroy()
    return True

then the MainLoop() exits as expected and python exits :)

You have kind of an unusual situation here.  Remember that wx.App.OnInit runs before the MainLoop starts.  Thus, there is no one monitoring for and dispatching messages for your main thread.  The main window has not been created yet, because no one has processed the creation messages.  The ProgressDialog should be modal, which means it spawns its own message loop, but if it's waiting for interaction with a parent window, that would be Bad.

I know this doesn't help you, and your app works fine on Windows, but maybe it provides some insight into the mechanics.
-- 
Tim Roberts, [hidden email]
Providenza & Boekelheide, Inc.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed (was: OnInit does not return and app hangs)

Brendan Simon-3
In reply to this post by Boštjan Mejak-4
On Thursday, 18 June 2015 18:48:15 UTC+10, Boštjan Mejak wrote:
What I would do is this:

with MyProgressDialog(title, message, maximum) as dlg:
    dlg.Update(0, new_message)

This doesn't solve the problem.  It's just another way of doing the same thing I was doing.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed

Brendan Simon-3
In reply to this post by Tim Roberts
On Friday, 19 June 2015 02:49:03 UTC+10, Tim Roberts wrote:
Brendan Simon (eTRIX) wrote:
I've narrowed the issue down to wx.ProgressDialog.Update().

If I do:
    dlg = MyProgressDialog(title, message, maximum)
    dlg.Destroy()
    return True

then the MainLoop() exits as expected and python exits :)

You have kind of an unusual situation here.  Remember that wx.App.OnInit runs before the MainLoop starts.  Thus, there is no one monitoring for and dispatching messages for your main thread.  The main window has not been created yet, because no one has processed the creation messages.  The ProgressDialog should be modal, which means it spawns its own message loop, but if it's waiting for interaction with a parent window, that would be Bad.

I know this doesn't help you, and your app works fine on Windows, but maybe it provides some insight into the mechanics.
I didn't realise exactly what I was doing.  I thought the application main code went in OnInit().  But now that you've informed me that MainLoop() needs to run, then it is clear that OnInit() needs to return and the main app code needs to run after MainLoop has exited (which seems weird as I assumed the no more processing of events would occur, but that's obviously not the case).

So I tried renaming OnInit() to run() and having an empty (return True) OnInit(), and then calling app.run() after MainLoop().  Guess what?  It seems to work and the ProgressDialog closes as expected :)
Thanks heaps for the pointer.

#----------------------------------------------------------------------------
def main_test():
     """Main test function."""
     app = MyApp("my arguments")
     app.MainLoop()
     app.run()
#----------------------------------------------------------------------------


So this begs the question: what should go in OnInit() and what should not, or be run outside of OnInit() ??
I wonder if using CallAfter(run) might be the recommended solution, instead of calling run() explicitly after MainLoop() ??

Cheers, Brendan.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed (was: OnInit does not return and app hangs)

Igor Korot
In reply to this post by Brendan Simon-3
Hi,

On Fri, Jun 19, 2015 at 2:44 AM, Brendan <[hidden email]> wrote:

> On Thursday, 18 June 2015 18:48:15 UTC+10, Boštjan Mejak wrote:
>>
>> What I would do is this:
>>
>> with MyProgressDialog(title, message, maximum) as dlg:
>>     dlg.Update(0, new_message)
>
>
> This doesn't solve the problem.  It's just another way of doing the same
> thing I was doing.

Can't you just create a hidden wx.Frame and make you progress dialog a child?

Thank you.

>
> --
> 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 [hidden email].
> For more options, visit https://groups.google.com/d/optout.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed

Tim Roberts
In reply to this post by Brendan Simon-3
Brendan wrote:

I didn't realise exactly what I was doing.  I thought the application main code went in OnInit().  But now that you've informed me that MainLoop() needs to run, then it is clear that OnInit() needs to return and the main app code needs to run after MainLoop has exited (which seems weird as I assumed the no more processing of events would occur, but that's obviously not the case).

So I tried renaming OnInit() to run() and having an empty (return True) OnInit(), and then calling app.run() after MainLoop().  Guess what?  It seems to work and the ProgressDialog closes as expected :)
...

So this begs the question: what should go in OnInit() and what should not, or be run outside of OnInit() ??
I wonder if using CallAfter(run) might be the recommended solution, instead of calling run() explicitly after MainLoop() ??

I hesitate to offer advice on "should" and "shouldn't", just because I'm not immersed in wxPython on a daily basis.

I can, however, draw parallels between a wxPython app and a traditional Windows SDK GUI app.  In a traditional Windows app, your main program is typically rather small.  You do command-line processing, you might set up the log file, you might load some DLLs -- mostly non-UI-related stuff.  That corresponds to wx.App.OnInit.

Once that non-UI setup is complete, you create the main window, and enter the message loop.  That's the call to wx.App.MainLoop.  All of the UI-related setup goes in the main window's WM_CREATE handler.

I should also say that it is POSSIBLE you have simply encountered a bug that only manifests itself in OS X.  As I mentioned, the code you posted runs perfectly fine in Windows.
-- 
Tim Roberts, [hidden email]
Providenza & Boekelheide, Inc.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: OnInit does not return and app hangs

Dev Player
In reply to this post by Brendan Simon (eTRIX)
Make sure you are destroying all top level "frames"/windows/dialogs including the ones that are -not Shown- or are -hidden-.
Also if you have threads running that you didn't shut down or other system resources like wx.Timer() that need explicit "destruction" or stopping are taken care of. Also try adding a def OnExit(self,...) method to your "myapp" with a print() to see if that gets hit.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: wx.ProgressDialog not destroyed

Robin Dunn
In reply to this post by Tim Roberts
Tim Roberts wrote:
> I should also say that it is POSSIBLE you have simply encountered a bug
> that only manifests itself in OS X.  As I mentioned, the code you posted
> runs perfectly fine in Windows.

Yes, wxOSX has some glitches when dialogs are used within OnInit and
there are not any other top-level windows created.  But I thought it was
just for native dialogs like wx.MessageDialog (the progress dialog is
generic on OSX last I checked) but perhaps it is a related issue in this
case.

This workflow could probably work and ends up being a little cleaner IMO
than calling a method after MainLoop returns:

* Create a Frame in OnInit (or before MainLoop is called if using wx.App
directly.)

* Also do wx.CallAfter(someFunctionOrMethod)

* Call MainLoop.  After the main loop starts it will process pending
events and then someFunctionOrMethod will be called, and you can show
the progress dialog and do your work there.

* When the task is finished then someFunctionOrMethod can Destroy() the
progress dialog and Close() the frame.  After someFunctionOrMethod
returns those two pending events will be processed and then MainLoop
should exit normally.


--
Robin Dunn
Software Craftsman
http://wxPython.org

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.