[wxPython] Three things

I'm working on a moderately complex project with wxPython and have
enountered some issues along the way. Maybe they're real, maybe they're
stupid people tricks, but here they are:

The app's primary interface is a taskbar icon, which is set up in my wxApp's
OnInit. However, before the taskbar icon can be used, I need to log in the
user, and the login window is a bit more complex than a simple dialog. This
produced two issues:

(1) For some reason, sizers don't work as expected with wxDialog-based
objects. The dialog included two wxStaticBoxSizers and within one of them a
bmp for a logo. What appeared to be perfectly good flags and options for
the sizers made the dialog an unreadable mess, with the controls piling up
on each other and on top of the bmp. Further, even when I was able to find
the 'magic' flags, I never could get the wxStaticBox element of the
wxStaticBoxSizers to display unless I resized the dialog.

Here's the fun part: I had constructed the object so that all I had to do
was change two lines to take it from a wxDialog class to wxFrame class. As
SOON as I did this, added a panel to the frame, and added pointed the sizers
to the panel -- everything worked *perfectly*.

So why is this? I haven't looked at the source (c) yet, but is it possible
that when we assign a sizer to a wxDialog, it's assigned to the dialog's
frame instead of its panel?

Okay, next thing: one reason I wanted to use a wxDialog in the first place
was to use the modal feature of wxDialog. Not having that, I tried out the
MakeModal() method for wxFrame. I've tried everything I can think of and it
isn't doing the trick -- IS there a trick, or is it (as the docs say) not
implemented?

Finally: what is the best way for a wxFrame-based class to communicate back
to the parent? By this I mean, I want to pass a 'user' object or at least
some sort of status back to my wxApp once I'm done. If I can't use
MakeModal, how do I get a nice orderly chain of events here?

The source code is pretty huge, but if needed....

PS: OK, actually, here's the FINALLY -- am I missing something, or is there
no way to set the state of a wxCheckBox at time of creation?

// Jeff Grimmett
// http://www.livejournal.com/users/grimmtooth/
  `--------------------------------------------'

(1) For some reason, sizers don't work as expected
with wxDialog-based objects. The dialog included two
wxStaticBoxSizers and within one of them a bmp for a
logo. What appeared to be perfectly good flags and
options for the sizers made the dialog an unreadable
mess, with the controls piling up on each other and on
top of the bmp. Further, even when I was able to find
the 'magic' flags, I never could get the wxStaticBox
element of the wxStaticBoxSizers to display unless I
resized the dialog.

Here's the fun part: I had constructed the object so
that all I had to do was change two lines to take it
from a wxDialog class to wxFrame class. As SOON as I
did this, added a panel to the frame, and added pointed
the sizers to the panel -- everything worked *perfectly*.

So why is this? I haven't looked at the source (c) yet,
but is it possible that when we assign a sizer to a
wxDialog, it's assigned to the dialog's frame instead
of its panel?

In the first place, wxDialog is not a 'frame' nor does it *have* a
frame. In the second place, wxDialog is derived from wxPanel, so it
*is* a panel. Third, I have used sizers in a wxDialog before with
no problems, so perhaps if you could send the *relevant* source
code... :slight_smile:

Okay, next thing: one reason I wanted to use a
wxDialog in the first place was to use the modal
feature of wxDialog. Not having that, I tried out
the MakeModal() method for wxFrame.

MakeModal() does not appear to be implemented for any wxWindows,
and wxDialog.SetModal() is deprecated. The method you want is
wxDialog.ShowModal(). wxFrame does not have this method.

Finally: what is the best way for a wxFrame-based
class to communicate back to the parent? By this
I mean, I want to pass a 'user' object or at least
some sort of status back to my wxApp once I'm done.
If I can't use MakeModal, how do I get a nice orderly
chain of events here?

Here is a reduced version of how I have tackled log-in. If you wish
I could send you the full code.

···

--- Grimmtooth <grimmtooth@softhome.net> wrote:

from wxPython.wx import *

class MyApp(wxApp):

    def OnInit(self):
        self.splash = wxFrame(None, -1, 'splash')
        self.splash.Show(true)
        userId = self.__Login()
        if userId == None:
            dlg = wxMessageDialog(self.splash,
                                  'Invalid provider information',
                                  'Unable to initialize Prism',
                                  wxOK | wxICON_INFORMATION)
            dlg.ShowModal()
            dlg.Destroy()
            self.splash.Close(true)
            return true
        
        frame = wxFrame(None, -1, 'application')
        frame.Show(true)
        self.SetTopWindow(frame)
        self.splash.Close(true)
        return true

    def __Login(self):
        login = LoginDialog(self.splash, -1)
        user = login.GetValues()
        print user
        return user[0]

class LoginDialog(wxDialog):
    def __init__(self, parent, id=-1, title='Login',
                 pos=wxDefaultPosition,
                 size=wxSize(250, 150),
                 text='Please type your username and password:',
                 username=''):
        wxDialog.__init__(self, parent, id, title, pos, size)
        self.myText = wxStaticText(self, -1, text,
                                   wxPoint(15, 5))
        wxStaticText(self, -1, 'User name: ', wxPoint(20, 30))
        wxStaticText(self, -1, 'Password: ', wxPoint(20, 55))
        self.nameBox = wxTextCtrl(self, -1, username,
                                  wxPoint(80,30),
                                  wxSize(120, -1))
        self.passwordBox = wxTextCtrl(self, -1, '', wxPoint(80,55),
                                 wxSize(120, -1),
                                 style=wxTE_PASSWORD)
        wxButton(self, wxID_OK, ' OK ', wxPoint(35, 90),
                 wxDefaultSize).SetDefault()
        wxButton(self, wxID_CANCEL, ' Cancel ', wxPoint(135, 90),
                 wxDefaultSize)
        self.nameBox.SetFocus()

    def GetValues(self):
        val = self.ShowModal()
        if val == wxID_OK:
            username = self.nameBox.GetValue()
            password = self.passwordBox.GetValue()
## h = sha.new(self.passwordBox.GetValue())
## password = h.hexdigest()
            return [username, password]
        else:
            return None

def Main():
    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    Main()

PS: OK, actually, here's the FINALLY -- am I missing
something, or is there no way to set the state of a
wxCheckBox at time of creation?

Have you tried wxCheckBox.SetValue()?

=====
Donnal Walter
Arkansas Children's Hospital

__________________________________________________
Do You Yahoo!?
Yahoo! Games - play chess, backgammon, pool and more
http://games.yahoo.com/

Dialogs have a wart in that, on MSW, they don't call Layout() during initialisation. Explicitly call Layout() at the end of your __init__() method to get the same layout as you see in a frame-hosted panel. The default OnSize handler calls Layout, so that's what was fixing the layout when you resized.

HTH,
Mike

···

--- Grimmtooth <grimmtooth@softhome.net> wrote:

(1) For some reason, sizers don't work as expected
with wxDialog-based objects. The dialog included two
wxStaticBoxSizers and within one of them a bmp for a
logo. What appeared to be perfectly good flags and
options for the sizers made the dialog an unreadable
mess, with the controls piling up on each other and on
top of the bmp. Further, even when I was able to find
the 'magic' flags, I never could get the wxStaticBox
element of the wxStaticBoxSizers to display unless I
resized the dialog.

...

Donnal Walter wrote:

> So why is this? I haven't looked at the source (c) yet,
> but is it possible that when we assign a sizer to a
> wxDialog, it's assigned to the dialog's frame instead
> of its panel?

In the first place, wxDialog is not a 'frame' nor does it *have* a
frame. In the second place, wxDialog is derived from wxPanel, so it
*is* a panel. Third, I have used sizers in a wxDialog before with
no problems, so perhaps if you could send the *relevant* source
code... :slight_smile:

Actually, I believe that in recent versions of wxPython/wxWindows,
wxDialog and wxPanel are no longer related (other than a common
ancestor of wxWindow). Other than that, though, Donnal is correct.
Sizers *do* work inside of wxDialogs, but you might have to nudge the
Layout() method. Another possibility, would be to set up the wxPanel,
but make the panel a child of your dialog. However, I don't think the
extra layer of redirection is necessary. (It could be useful if you
expected to use the same set of controls as either a dialog or a normal
frame, though.)

Jeff Shannon
Technician/Programmer
Credit International

···

--- Grimmtooth <grimmtooth@softhome.net> wrote:

In the first place, wxDialog is not a 'frame' nor does it *have* a
frame. In the second place, wxDialog is derived from wxPanel, so it
*is* a panel.

It's not anymore. wxDialog now derives from the same class that wxFrame
does, wxTopLevelWindow, and also the same mix-in class that wxPanel does.

MakeModal() does not appear to be implemented for any wxWindows,

It is for wxFrame, and works fairly well.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com Java give you jitters?
http://wxPython.org Relax with wxPython!

Dialogs have a wart in that, on MSW, they don't call Layout() during
initialisation.

Technically, the problem is that there is no size event when shown like
wxFrame usually does. Layout is called from the default EVT_SIZE handler.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com Java give you jitters?
http://wxPython.org Relax with wxPython!

Dialogs have a wart in that, on MSW, they don't call Layout() during
initialisation. Explicitly call Layout() at the end of your __init__()
method to get the same layout as you see in a frame-hosted panel. The
default OnSize handler calls Layout, so that's what was fixing the
layout when you resized.

Tried that. I tried self.Layout() for the dialog, self.sizer.Layout, and
having each sub-sizer call Layout() as well, even though if I understand the
docs, that should not have been necessary. No combination gave me good
results :frowning:

// Jeff Grimmett
// http://www.livejournal.com/users/grimmtooth/
  `--------------------------------------------'

Layout() method. Another possibility, would be to set up the wxPanel,
but make the panel a child of your dialog. However, I don't think the

I've been considering this, no matter HOW ugly it looks code-wise :slight_smile:

extra layer of redirection is necessary. (It could be useful if you
expected to use the same set of controls as either a dialog or a normal
frame, though.)

Yah, that's what is so frustrating -- it seems to me that they should work
the same on either. (sigh)

// Jeff Grimmett
// http://www.livejournal.com/users/grimmtooth/
  `--------------------------------------------'

> MakeModal() does not appear to be implemented for any wxWindows,

It is for wxFrame, and works fairly well.

Is there a trick to it or something? Or maybe I should be asking, 'in what
version?' :slight_smile:

// Jeff Grimmett
// http://www.livejournal.com/users/grimmtooth/
  `--------------------------------------------'