Restarting an app during runtiime

Hi all,

This is my first post.

I have a program that requires information from the user before the
main frame of the GUI is begun. To obtain the information I use a
series of dialogs before adding the main widgets.

So it goes something like

class mainFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.frame.__init__(self, parent, title = title)
        dlg = MyFirstDialog(self, -1, 'title1')
        dlg.CenterOnScreen()
        val = dlg.ShowModal()
        if val == wx.ID_OK:
            global dlgVariables
            dlgVariables = dlg.VariableBoxes.GetValue()
        dlg.Destroy()
        dlg2 = MySecondDialog(self, -1, 'title1')
        dlg2.CenterOnScreen()
        val2 = dlg2.ShowModal()
        if val2 == wx.ID_OK:
            global dlg2Variables
            dlg2Variables = dlg2.VariableBoxes.GetValue()
        dlg2.Destroy()
        self.CreateMainGUI()

    def CreateMainGUI(self):
        #Here I make panels, sliders and images. There is also a
button called self.restartButton

All of this code works great. When the program starts a dialog
appears. When OK is clicked a second dialog appears whose layout
depends on the choices made in the first dialog. When choices are made
on this dialog the main GUI is drawn and it's layout depends on
choices made.

My problem is that it may become apparent to the user that he/she
needs to change his/her mind regarding some of the choices made and
restart the program so that the main window disappears and the first
dialog reappears. The mainGUI will also have been saving some of the
choices of the user up to files to this point and those choices must
be wiped so that the user can start again.

I tried the following method:

Inside CreateMainGUI is the method OnRestart bound with an event
binder to the restart button.

        def OnRestart(self, event):
            the_wd = os.getcwd()
            tFile = the_wd + 'saves.txt'
            if os.path.exists(tFile) == True:
                os.remove(tFile)
            global restart
            restart = True
            self.Close()

Now the way I begin the program is to have the following 4 lines at
the end of the file where all these classes exist:

app = wx.App(False)
frame = mainFrame(None, 'Main Frame')
frame.Show()
app.MainLoop()

Then I cal call python MyFile.py from the command line. This works
fine. Now, to facilitate restarting I tried the following instead

global restart
restart = False
app = wx.App(False)
frame = mainFrame(None, 'Main Frame')
frame.Show()
app.MainLoop()
while restart:
    app = wx.App(False)
    frame = mainFrame(None, 'Main Frame')
    frame.Show()
    app.MainLoop()

With this code the program starts and works fine until restart is
pressed at which point I get an error.

The error is to do with my calling wx.GetDisplaySize() at some point
in the code. It says

Traceback (most recent call last):
    File "myFile.py' line 320 in <module>
        frame = mainFrame(None, 'Main Frame')
    File 'myFile.py', line 90, in __init__
        disHeight = wx.GetDisplaySize()[1]
    File "//usr/local/lib/wxpython-unicode-2.812.0/lib/python2.6/site-
packages/wx-2.8-max-unicode/wx/_misc.py", line 523 in GetDisplaySize
        return _misc_.GetDisplaySize(*args)
wx._core.PyNoAppError: The wx.App object must be created first!

I don't understand this as the line that fails is coming after app =
wx.App(False). As I say, the code works fine up until the while loop
so my use of GetDisplaySize() is fine. When it enters the while loop
it seems not to be creating the second app. I'm sorry I couldn't put
all of the code up. The MainGUI uses rpy2 to draw pictures from
sensitive data I have on disc so it couldn't really be tested anyway.

Thanks in advance for your thoughts on this

Danny

Hi all,

This is my first post.

I have a program that requires information from the user before the
main frame of the GUI is begun. To obtain the information I use a
series of dialogs before adding the main widgets.

So it goes something like

class mainFrame(wx.Frame):
     def __init__(self, parent, title):
         wx.frame.__init__(self, parent, title = title)
         dlg = MyFirstDialog(self, -1, 'title1')
         dlg.CenterOnScreen()
         val = dlg.ShowModal()
         if val == wx.ID_OK:
             global dlgVariables
             dlgVariables = dlg.VariableBoxes.GetValue()
         dlg.Destroy()
         dlg2 = MySecondDialog(self, -1, 'title1')
         dlg2.CenterOnScreen()
         val2 = dlg2.ShowModal()
         if val2 == wx.ID_OK:
             global dlg2Variables
             dlg2Variables = dlg2.VariableBoxes.GetValue()
         dlg2.Destroy()
         self.CreateMainGUI()

     def CreateMainGUI(self):
         #Here I make panels, sliders and images. There is also a
button called self.restartButton

First of all, I would not do this in the Frame class. The dialogs are needed to know how to construct a frame, but they are not the frame nor part of it. Instead I think it would make sense for you to derive a class from wx.App and do the dialogs and frame construction in the OnInit method.

Second, "series of dialogs" makes me think that using a wx.wizard.Wizard would be a better solution for that part of the startup.

All of this code works great. When the program starts a dialog
appears. When OK is clicked a second dialog appears whose layout
depends on the choices made in the first dialog. When choices are made
on this dialog the main GUI is drawn and it's layout depends on
choices made.

My problem is that it may become apparent to the user that he/she
needs to change his/her mind regarding some of the choices made and
restart the program so that the main window disappears and the first
dialog reappears. The mainGUI will also have been saving some of the
choices of the user up to files to this point and those choices must
be wiped so that the user can start again.

I tried the following method:

Inside CreateMainGUI is the method OnRestart bound with an event
binder to the restart button.

         def OnRestart(self, event):
             the_wd = os.getcwd()
             tFile = the_wd + 'saves.txt'
             if os.path.exists(tFile) == True:
                 os.remove(tFile)
             global restart
             restart = True
             self.Close()

Now the way I begin the program is to have the following 4 lines at
the end of the file where all these classes exist:

app = wx.App(False)
frame = mainFrame(None, 'Main Frame')
frame.Show()
app.MainLoop()

Then I cal call python MyFile.py from the command line. This works
fine. Now, to facilitate restarting I tried the following instead

global restart
restart = False
app = wx.App(False)
frame = mainFrame(None, 'Main Frame')
frame.Show()
app.MainLoop()
while restart:
     app = wx.App(False)
     frame = mainFrame(None, 'Main Frame')
     frame.Show()
     app.MainLoop()

With this code the program starts and works fine until restart is
pressed at which point I get an error.

The error is to do with my calling wx.GetDisplaySize() at some point
in the code. It says

Traceback (most recent call last):
     File "myFile.py' line 320 in<module>
         frame = mainFrame(None, 'Main Frame')
     File 'myFile.py', line 90, in __init__
         disHeight = wx.GetDisplaySize()[1]
     File "//usr/local/lib/wxpython-unicode-2.812.0/lib/python2.6/site-
packages/wx-2.8-max-unicode/wx/_misc.py", line 523 in GetDisplaySize
         return _misc_.GetDisplaySize(*args)
wx._core.PyNoAppError: The wx.App object must be created first!

I don't understand this as the line that fails is coming after app =
wx.App(False). As I say, the code works fine up until the while loop
so my use of GetDisplaySize() is fine. When it enters the while loop
it seems not to be creating the second app. I'm sorry I couldn't put
all of the code up. The MainGUI uses rpy2 to draw pictures from
sensitive data I have on disc so it couldn't really be tested anyway.

wx.App does a number of things that depend on the assumption that there is only 1 instance of wx.App ever created for the life of the process. Some people have been able to get things to work with a new app object created after another has been disposed of, but it's not recommended.

However if you follow the advice above and implement your own wx.App class with the dialogs/frame being created in OnInit then doing a restart of things should end up being fairly easy. For example, your OnRestart could be as simple as this:

     def OnRestart(self, evt):
         self.doMyCleanup()
  self.Close()
  wx.GetApp().OnInit()

Although since OnInit has special meaning you may want to move the guts of OnInit to another method that you call from OnInit and from OnRestart.

···

On 7/26/11 3:27 AM, Danny Williamson wrote:

--
Robin Dunn
Software Craftsman

Hi Robin,

Thanks for this. Could I just have a few details about how the OnInit
method works? I am fairly new to python and most of my work has been
with frames and panels.

Are there any examples in the tutorial?

Danny

···

On Jul 26, 7:09 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 7/26/11 3:27 AM, Danny Williamson wrote:

> Hi all,

> This is my first post.

> I have a program that requires information from the user before the
> main frame of the GUI is begun. To obtain the information I use a
> series of dialogs before adding the main widgets.

> So it goes something like

> class mainFrame(wx.Frame):
> def __init__(self, parent, title):
> wx.frame.__init__(self, parent, title = title)
> dlg = MyFirstDialog(self, -1, 'title1')
> dlg.CenterOnScreen()
> val = dlg.ShowModal()
> if val == wx.ID_OK:
> global dlgVariables
> dlgVariables = dlg.VariableBoxes.GetValue()
> dlg.Destroy()
> dlg2 = MySecondDialog(self, -1, 'title1')
> dlg2.CenterOnScreen()
> val2 = dlg2.ShowModal()
> if val2 == wx.ID_OK:
> global dlg2Variables
> dlg2Variables = dlg2.VariableBoxes.GetValue()
> dlg2.Destroy()
> self.CreateMainGUI()

> def CreateMainGUI(self):
> #Here I make panels, sliders and images. There is also a
> button called self.restartButton

First of all, I would not do this in the Frame class. The dialogs are
needed to know how to construct a frame, but they are not the frame nor
part of it. Instead I think it would make sense for you to derive a
class from wx.App and do the dialogs and frame construction in the
OnInit method.

Second, "series of dialogs" makes me think that using a wx.wizard.Wizard
would be a better solution for that part of the startup.

> All of this code works great. When the program starts a dialog
> appears. When OK is clicked a second dialog appears whose layout
> depends on the choices made in the first dialog. When choices are made
> on this dialog the main GUI is drawn and it's layout depends on
> choices made.

> My problem is that it may become apparent to the user that he/she
> needs to change his/her mind regarding some of the choices made and
> restart the program so that the main window disappears and the first
> dialog reappears. The mainGUI will also have been saving some of the
> choices of the user up to files to this point and those choices must
> be wiped so that the user can start again.

> I tried the following method:

> Inside CreateMainGUI is the method OnRestart bound with an event
> binder to the restart button.

> def OnRestart(self, event):
> the_wd = os.getcwd()
> tFile = the_wd + 'saves.txt'
> if os.path.exists(tFile) == True:
> os.remove(tFile)
> global restart
> restart = True
> self.Close()

> Now the way I begin the program is to have the following 4 lines at
> the end of the file where all these classes exist:

> app = wx.App(False)
> frame = mainFrame(None, 'Main Frame')
> frame.Show()
> app.MainLoop()

> Then I cal call python MyFile.py from the command line. This works
> fine. Now, to facilitate restarting I tried the following instead

> global restart
> restart = False
> app = wx.App(False)
> frame = mainFrame(None, 'Main Frame')
> frame.Show()
> app.MainLoop()
> while restart:
> app = wx.App(False)
> frame = mainFrame(None, 'Main Frame')
> frame.Show()
> app.MainLoop()

> With this code the program starts and works fine until restart is
> pressed at which point I get an error.

> The error is to do with my calling wx.GetDisplaySize() at some point
> in the code. It says

> Traceback (most recent call last):
> File "myFile.py' line 320 in<module>
> frame = mainFrame(None, 'Main Frame')
> File 'myFile.py', line 90, in __init__
> disHeight = wx.GetDisplaySize()[1]
> File "//usr/local/lib/wxpython-unicode-2.812.0/lib/python2.6/site-
> packages/wx-2.8-max-unicode/wx/_misc.py", line 523 in GetDisplaySize
> return _misc_.GetDisplaySize(*args)
> wx._core.PyNoAppError: The wx.App object must be created first!

> I don't understand this as the line that fails is coming after app =
> wx.App(False). As I say, the code works fine up until the while loop
> so my use of GetDisplaySize() is fine. When it enters the while loop
> it seems not to be creating the second app. I'm sorry I couldn't put
> all of the code up. The MainGUI uses rpy2 to draw pictures from
> sensitive data I have on disc so it couldn't really be tested anyway.

wx.App does a number of things that depend on the assumption that there
is only 1 instance of wx.App ever created for the life of the process.
Some people have been able to get things to work with a new app object
created after another has been disposed of, but it's not recommended.

However if you follow the advice above and implement your own wx.App
class with the dialogs/frame being created in OnInit then doing a
restart of things should end up being fairly easy. For example, your
OnRestart could be as simple as this:

 def OnRestart\(self, evt\):
     self\.doMyCleanup\(\)
    self\.Close\(\)
    wx\.GetApp\(\)\.OnInit\(\)

Although since OnInit has special meaning you may want to move the guts
of OnInit to another method that you call from OnInit and from OnRestart.

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Hi Robin,

Thanks for this. Could I just have a few details about how the OnInit
method works? I am fairly new to python and most of my work has been
with frames and panels.

OnInit is called from within the wx.App.__init__ after the platform and GUI toolkits have been initialized. It's purpose is to create the initial state of the GUI and then return True to indicate success. A False return value will cause the program to exit.

Are there any examples in the tutorial?

The demo's Main.py uses a derived class with OnInit. Some of the examples in the book also use a derived wx.App class.

···

On 7/28/11 3:56 AM, Danny Williamson wrote:

--
Robin Dunn
Software Craftsman