[wxPython] Problems with wxPySimpleApp() to open modal dialogs

Hi,

in my application I need the ability to open some easy dialogs.
I rummage the wxPython sources and found the class wxPySimpleApp().
Now, with this class, I can open common dialogs like this:

    from wxPython.wx import *

    wxPySimpleApp()
    dlg = wxDirDialog(None)
    if dlg.ShowModal() == wxID_OK:
        print 'You selected: %s\n' % dlg.GetPath()
    dlg.Destroy()

And now my problem:
If I use no common dialog but my own dialog, the first run was fine. But on
next start I get the error message "Only 1 wxApp per process!".

    from wxPython.wx import *

    wxPySimpleApp()
    dlg = wxDialog(None, -1, "Test")
    dlg.ShowModal()
    dlg.Destroy()

What's the different between common dialogs and wxDialog ?

I hope somebody can help me.

Thanks
Dirk

···

_______________________________________________
wxPython-users maillist - wxPython-users@starship.python.net
http://starship.python.net/mailman/listinfo/wxpython-users

Hello Dirk,

At the bottom I've attached a simple example which uses dialog boxes.
Its old code but it might help.

Regards,
Bob

Dirk Hameier wrote:

Hi,

in my application I need the ability to open some easy dialogs.
I rummage the wxPython sources and found the class wxPySimpleApp().
Now, with this class, I can open common dialogs like this:

    from wxPython.wx import *

    wxPySimpleApp()
    dlg = wxDirDialog(None)
    if dlg.ShowModal() == wxID_OK:
        print 'You selected: %s\n' % dlg.GetPath()
    dlg.Destroy()

And now my problem:
If I use no common dialog but my own dialog, the first run was fine. But on
next start I get the error message "Only 1 wxApp per process!".

    from wxPython.wx import *

    wxPySimpleApp()
    dlg = wxDialog(None, -1, "Test")
    dlg.ShowModal()
    dlg.Destroy()

What's the different between common dialogs and wxDialog ?

I hope somebody can help me.

Thanks
Dirk

from wxPython.wx import *
#from string import *
import string

ID_EXIT = 103
ID_DIALOG1 = 110

class mtFrame(wxFrame):
    def __init__(self, parent, ID, title):
        wxFrame.__init__(self, parent, ID, title, wxDefaultPosition,
wxSize(500, 400))
        self.radioSelection = 0

        # Construct a StatusBar - class is defined below
        statusBar1 = mtStatusBar(self,-1)
        self.SetStatusBar(statusBar1)

        # Construct "File" menu
        menuBar = wxMenuBar()
        menuFile = wxMenu()
        menuFile.Append(ID_EXIT, "E&xit", "Terminate the program")
        EVT_MENU(self, ID_EXIT, self.OnExit)
        menuBar.Append(menuFile, "&File");
        # Construct "View" menu
        menuView = wxMenu()
        menuView.Append(1100, "&Custom dialog", "display custom dialog")
        EVT_MENU(self, 1100, self.DisplayDialog1)
        menuView.Append(1101, "&Radio button dialog", "Radio button
dialog")
        EVT_MENU(self, 1101, self.DisplayRadioButtonDialog)

        menuView.Append(1102, "&Sizer dialog", "Sizer dialog")
        EVT_MENU(self, 1102, self.DisplaySizerDialog)

        menuBar.Append(menuView, "&View");
        self.SetMenuBar(menuBar)

    def DisplayDialog1(self, event):
        d = mtDialog(self,-1)
        d.Centre()
        val = d.ShowModal()
        if val == wxID_OK:
            self.SetStatusText("Ready",1)
        d.Destroy()

    def DisplayRadioButtonDialog(self, event):
        d = radioDialog(self,-1)
        #d = sizerRadioDialog(self,-1)
        d.Centre()
        val = d.ShowModal()
        if val == wxID_OK:
            radioSetting = d.getSelection()
            self.SetStatusText("radioSetting=%d" % radioSetting,0)
        d.Destroy()

    def DisplaySizerDialog(self, event):
        d = sizerDialog(self,"sample dialog")
        d.Centre()
        d.setType(self.radioSelection)
        val = d.ShowModal()
        if val == wxID_OK:
            self.radioSelection = d.getType()
            tt = d.getText()
            self.SetStatusText("selection=%d text=%s" %
                               (self.radioSelection, tt),0)
        else:
            self.SetStatusText("Cancel",0)
        d.Destroy()

    def SetStatusBar2ToReady(self, event): # called from a dialog box
        self.SetStatusText("Ready",2)

    def OnCloseWindow(self, event):
        self.Destroy()

    def OnExit(self, event):
        self.Close(true)

···

#--------------------------------------------------------------------

# This way the OK and Cancel button will always be positioned right
# no matter what the size of the dialog is.
class sizerDialog(wxDialog):
    def __init__(self,parent,title):
        wxDialog.__init__(self,parent,-1,title)

        box = wxBoxSizer(wxVERTICAL)
        box1 = wxBoxSizer(wxHORIZONTAL)
        # Add the panel to which widgets will be added
        panel = wxPanel(self,-1,size=(140,220)) # panel must big enough
to hold all widgets
        box1.Add(panel,0,wxALL,5)
        box.Add(box1,0,wxALL,2)
        boxX = wxBoxSizer(wxHORIZONTAL)
        okButton = wxButton(self,wxID_OK,"OK")
        okButton.SetDefault()
        cancelButton = wxButton(self,wxID_CANCEL,"Cancel")
        boxX.Add(15,20,0,wxEXPAND)
        boxX.Add(okButton,0, wxALL, 5)
        boxX.Add(10,20,0,wxEXPAND)
        boxX.Add(cancelButton,0, wxALL, 5)
        boxX.Add(10,20,0,wxEXPAND)
        box.Add(boxX,0,wxCENTER)
        self.SetAutoLayout(true)
        self.SetSizer(box)
        box.Fit(self)
        box.SetSizeHints(self)

        # Add stuff to the panel here
        sampleList = ['zero ', 'one', 'two', 'three']
        position = wxPoint(40,5)
        numberOfColumns = 1
        self.rb = wxRadioBox(panel, 10, "label title", position,
wxDefaultSize,
                        sampleList, numberOfColumns, wxRA_SPECIFY_COLS)

        wxStaticText(panel, -1, "Text here",wxPoint(5,140))
        self.t = wxTextCtrl(panel, 10, "128", wxPoint(80,135),
wxSize(40,20))
        EVT_TEXT(panel, 10, self.EvtText) # checks every key stroke

    def getType(self):
        return self.rb.GetSelection()

    def setType(self, type):
        self.rb.SetSelection(type)

    def getText(self):
        return self.t.GetLineText(0)

    def EvtText(self, event): # check every key stroke for validity
        s = event.GetString()
        try:
            i = string.atoi(s)
            print i
            if i < 0 or i > 255:
                print 'must be between 0 and 255'
        except ValueError:
            print 'must be a number'
        
#-------------------------------------------------------------------------------------

# This works fine
class radioDialog(wxDialog):
    def __init__(self,parent,ID):
       
wxDialog.__init__(self,parent,ID,"title",wxDefaultPosition,wxSize(200,200))
        panel = wxPanel(self, -1)
        self.selection = 0

        sampleList = ['zero ', 'one', 'two', 'three']
        numberOfColumns = 1
        self.rb = wxRadioBox(panel, 10, "label title", wxPoint(20,20),
wxDefaultSize,
                        sampleList, numberOfColumns, wxRA_SPECIFY_COLS)
        EVT_RADIOBOX(panel, 10, self.EvtRadioBox)
        self.okButton = wxButton(panel,wxID_OK,
"OK",wxPoint(20,160),wxDefaultSize)
        self.cancelButton = wxButton(panel,wxID_CANCEL,
"Cancel",wxPoint(105,160),wxDefaultSize)

    def EvtRadioBox(self, event):
        self.selection = event.GetInt()

    def getSelection(self):
        return self.selection
        
# Dialog box class. Displays a custom dialog box.
class mtDialog(wxDialog):
    def __init__(self,parent,ID):
       
wxDialog.__init__(self,parent,ID,"title",wxDefaultPosition,wxSize(200,150))
        panel = wxPanel(self, -1)
        txt = wxStaticText(panel, -1, "Text here",wxPoint(20,20))
        self.okButton = wxButton(panel,wxID_OK,
"OK",wxPoint(20,110),wxDefaultSize)
        self.cancelButton = wxButton(panel,wxID_CANCEL,
"Cancel",wxPoint(105,110),wxDefaultSize)
        self.readyButton = wxButton(panel,10,
"Ready",wxPoint(75,40),wxSize(60,25))
        EVT_BUTTON(panel,10,parent.SetStatusBar2ToReady) # calls parent
        self.enableButton = wxButton(panel,20,
"Enable",wxPoint(75,70),wxSize(60,25))
        EVT_BUTTON(panel,20,self.OnEnable) # calls inside this class

    def OnEnable(self, event):
        self.readyButton.Enable(FALSE) # doesn't work

# StatusBar class which sets up 3 status bars. StatusBar 1 has variable
size,
# statusbars 2 and 3 have a fixed width of 100 pixels
class mtStatusBar(wxStatusBar):
    def __init__(self,parent,ID):
        wxStatusBar.__init__(self,parent,ID)
        n = 3 # number of status bars
        w = [-1, 100, 100] # widths of each bar, -1 means variable
        self.SetFieldsCount(n)
        self.SetStatusWidths(w)

class mtApp(wxApp):
    def OnInit(self):
        frame = mtFrame(NULL, -1, "wxDialog4")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = mtApp(0)
app.MainLoop()

--
---------------------
Robert B. Klimek
NASA Glenn Research Center
robert.klimek@grc.nasa.gov
---------------------

_______________________________________________
wxPython-users maillist - wxPython-users@starship.python.net
http://starship.python.net/mailman/listinfo/wxpython-users

And now my problem:
If I use no common dialog but my own dialog, the first run was fine. But on
next start I get the error message "Only 1 wxApp per process!".

    from wxPython.wx import *

    wxPySimpleApp()
    dlg = wxDialog(None, -1, "Test")
    dlg.ShowModal()
    dlg.Destroy()

What's the different between common dialogs and wxDialog ?

Common dialogs are very thing wrappers around the system dialogs, they don't
actually create a wxWindow. To solve your problem you need to save a
reference to the app object and jump into MainLoop after your dialog closes.
This gives the cleanup code in wxApp a chance to 1. process any pending
events, and 2. delete windows that have been closed.

     from wxPython.wx import *

     app = wxPySimpleApp()
     dlg = wxDialog(None, -1, "Test")
     dlg.ShowModal()
     dlg.Destroy()
     app.MainLoop()

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com

wxPython has moved Check it out!

_______________________________________________
wxPython-users maillist - wxPython-users@starship.python.net
http://starship.python.net/mailman/listinfo/wxpython-users

This is a follow up question to a thread from quite a while back. I kept
it because I thought I would have a use for it, an indeed I do, but now
I have a question about it.

Robin Dunn wrote:

Common dialogs are very thing wrappers around the system dialogs, they don't
actually create a wxWindow. To solve your problem you need to save a
reference to the app object and jump into MainLoop after your dialog closes.
This gives the cleanup code in wxApp a chance to 1. process any pending
events, and 2. delete windows that have been closed.

     from wxPython.wx import *

     app = wxPySimpleApp()
     dlg = wxDialog(None, -1, "Test")
     dlg.ShowModal()
     dlg.Destroy()
     app.MainLoop()

This is a little too simple an example to be usefull. Most of the time,
you are going to want to call more than one dilaog box in a session, so
I tried this:

# Begin code###############################################
#!/usr/bin/env python
# a test of wxPySimpleApp

from wxPython.wx import *

app = wxPySimpleApp()

dlg = wxDialog(None, -1, "Test1",wxDefaultPosition,(100,100))
dlg.ShowModal()
dlg.Destroy()

dlg = wxDialog(None, -1, "Test2",wxDefaultPosition,(200,200))
dlg.ShowModal()
dlg.Destroy()

dlg = wxDialog(None, -1, "Test3",wxDefaultPosition,(300,300))
dlg.ShowModal()
dlg.Destroy()

dlg = wxDialog(None, -1, "This is the last",wxDefaultPosition,(400,400))
dlg.ShowModal()
dlg.Destroy()

app.MainLoop()

# END CODE ####################################################

This crashes with a "Segmentation fault (core dumped) "

Oddly enough, it seems to work fine if I only bring up three dialog
boxes, rather than four.

# BEGIN CODE ####################################################

#!/usr/bin/env python
# a test of wxPySimpleApp

from wxPython.wx import *

app = wxPySimpleApp()

dlg = wxDialog(None, -1, "Test1",wxDefaultPosition,(100,100))
dlg.ShowModal()
dlg.Destroy()

app.MainLoop()
app = wxPySimpleApp()

dlg = wxDialog(None, -1, "Test2",wxDefaultPosition,(200,200))
dlg.ShowModal()
dlg.Destroy()

app.MainLoop()
app = wxPySimpleApp()

dlg = wxDialog(None, -1, "Test3",wxDefaultPosition,(300,300))
dlg.ShowModal()
dlg.Destroy()

app.MainLoop()
app = wxPySimpleApp()

dlg = wxDialog(None, -1, "This is the last",wxDefaultPosition,(400,400))
dlg.ShowModal()
dlg.Destroy()

dlg = wxDialog(None, -1, "Just Kidding",wxDefaultPosition,(400,400))
dlg.ShowModal()
dlg.Destroy()

app.MainLoop()

# END CODE ####################################################

In this case, I get a lot of errors like:

GLib-CRITICAL **: file gmain.c: line 500 (g_source_remove): assertion
`tag > 0'
failed.

It does seem to work, in spite of the errors. I also tried putting a
"del(app)" in there before re-creating it, with no difference.

So, here ios what I want to do:

Have a procedural app, that isn't event driven, and doesn't have a main
window. I want it to start, do some stuff, occasionally ask the user a
question via a dialog box, and then end, with no limit on how many
questions can be asked before ending.

How do I do that?

-Chris

···

--
Christopher Barker,
Ph.D.
cbarker@jps.net --- --- ---
http://www.jps.net/cbarker -----@@ -----@@ -----@@
                                   ------@@@ ------@@@ ------@@@
Water Resources Engineering ------ @ ------ @ ------ @
Coastal and Fluvial Hydrodynamics ------- --------- --------
------------------------------------------------------------------------
------------------------------------------------------------------------