[wxPython] Message Watcher sizer help

I'm attempting to grasp sizers for use in PythonCard. So far I haven't had
much luck getting any desired layouts. As a simple test (or so I thought) I
tried to convert the Message Watcher window to use sizers instead of fixed
positions. The code below is the original source. I commented out the
EVT_SIZE binding in my own failed sizer attempts.

I've attached a picture to show what the window looks like. What I would
like the sizer to provide is the same kind of layout, but with the second
wxCheckBox aligned against the right side of the window. The wxTextCtrl
should grow with window. A bonus would be a minimal width and height for the
window. I currently have the controls on a panel to handle the resizing,
perhaps that is causing part of the problem?

I tried using a combination of nested wxBoxSizers with horizontal and
vertical layouts without success. I even tried doing the layout using
wxDesigner, where I came close, but I couldn't save the source and it never
worked quite right, perhaps because I didn't use spacers between the items?!

Any help would be appreciated,

ka

msg.jpg

···

---

class MessageWatcher( wxMiniFrame, EventListener) :
    def __init__(self, parent, ID, title, pos, size, parentApp ):
        wxMiniFrame.__init__(self, parent, ID, title, pos, size,
wxDEFAULT_FRAME_STYLE | wxTINY_CAPTION_HORIZ)
        panel = wxPanel(self, -1)

        self.parentApp = parentApp

        EVT_SIZE(self, self.onSize)
        EVT_CLOSE(self, self.onCloseMe)

        self.hideIdle = wxCheckBox(panel, -1, 'Hide idle', wxPoint(1, 1),
wxDefaultSize, wxNO_BORDER)
        self.hideIdle.SetValue(true)

        self.hideUnused = wxCheckBox(panel, -1, 'Hide unused', wxPoint(80,
1), wxDefaultSize, wxNO_BORDER)
        self.hideUnused.SetValue(true)

        self.msgHistory = wxTextCtrl(panel, -1, '', wxPoint(0, 30),
wxDefaultSize, style=wxTE_MULTILINE | wxTE_READONLY)

    def onSize(self, event):
        size = self.GetClientSize()
        self.msgHistory.SetSize(wxSize(size.width, size.height - 30))
        event.Skip()

Hi Kevin,

I have been attempting to grasp sizers for a project I am working
on as well. What I'd like to do is define a set of wxPanels that
use sizers internally, and then be able use these panels in frames,
miniframes, dialogs, or other panels. I don't claim to have a firm
handle on sizers yet, but the following code appears to behave
according to your requirements, at least as I understand them.

First, I changed wxMiniFrame to wxFrame simply to make it easier to
test. It SHOULD work the same with wxMiniFrame. Second, the wxFrame
has its own sizer, to which the wxPanel is added. Then in the
panel, I use a wxFlexGridSizer, so that the top row can have a
constant height and the bottom row be set growable. Then I add an
expandable spacer between the two check box controls. Cheers.

from wxPython.wx import *

class MessageWatcher(wxFrame) :
    def __init__(self, parent, ID, title, pos, size):
        wxFrame.__init__(self, parent, ID, title, pos, size,
                             wxDEFAULT_FRAME_STYLE |
                             wxTINY_CAPTION_HORIZ)
        sizer = wxBoxSizer(wxHORIZONTAL)
        item1 = PanelA(self, -1)
        sizer.AddWindow(item1, 1, wxEXPAND)
        sizer.Fit(self)
        sizer.SetSizeHints(self)
        self.SetAutoLayout(true)
        self.SetSizer(sizer)

class PanelA(wxPanel):
    def __init__(self, parent, id):
        wxPanel.__init__(self, parent, id)
        sizer1 = wxFlexGridSizer(0, 1, 5, 5)
        sizer1.AddGrowableRow(1)
        sizer1.AddGrowableCol(0)
        sizer2 = wxBoxSizer(wxHORIZONTAL)
        self.hideIdle = wxCheckBox(self, -1, 'Hide idle',
                                   wxDefaultPosition,
                                   wxDefaultSize, wxNO_BORDER)
        self.hideIdle.SetValue(true)
        sizer2.AddWindow(self.hideIdle, 0, wxALL, 5)
        sizer2.Add(5, 5, 1)

        self.hideUnused = wxCheckBox(self, -1, 'Hide unused',
                                     wxDefaultPosition,
                                     wxDefaultSize, wxNO_BORDER)
        self.hideUnused.SetValue(true)
        sizer2.AddWindow(self.hideUnused, 0, wxALL, 5)

        sizer1.AddSizer(sizer2, 0, wxEXPAND)
        self.msgHistory = wxTextCtrl(self, -1, '',
                                     wxDefaultPosition,
                                     wxSize(50,100),
                                     style=wxTE_MULTILINE |
                                     wxTE_READONLY)
        sizer1.AddWindow(self.msgHistory, 0, wxEXPAND)
        sizer1.Fit(self)
        sizer1.SetSizeHints(self)
        self.SetSizer(sizer1)
        self.SetAutoLayout(true)
        self.Layout()

class App(wxApp):
    def OnInit(self):
        frame = MessageWatcher(None, -1, 'Message Watcher',
                               wxDefaultPosition,
                               wxDefaultSize)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = App()
app.MainLoop()

···

--- Kevin Altis <altis@semi-retired.com> wrote:

I'm attempting to grasp sizers for use in PythonCard. So far I
haven't had much luck getting any desired layouts.
<snip>
I've attached a picture to show what the window looks like. What
I would like the sizer to provide is the same kind of layout,
but with the second wxCheckBox aligned against the right side of
the window. The wxTextCtrl should grow with window. A bonus would
be a minimal width and height for the window. I currently have
the controls on a panel to handle the resizing, perhaps that is
causing part of the problem?

I tried using a combination of nested wxBoxSizers with horizontal
and vertical layouts without success. <snip>

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

__________________________________________________
Do You Yahoo!?
Get email alerts & NEW webcam video instant messaging with Yahoo! Messenger

Attached are two images to demonstrate how the code that I posted
appears on my system. Hope this helps.

···

--- Kevin Altis <altis@semi-retired.com> wrote:

I've attached a picture to show what the window looks like. What
I would like the sizer to provide is the same kind of layout, but
with the second wxCheckBox aligned against the right side of the
window. The wxTextCtrl should grow with window. A bonus would be
a minimal width and height for the window.

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

__________________________________________________
Do You Yahoo!?
Get email alerts & NEW webcam video instant messaging with Yahoo! Messenger

Second, the wxFrame
has its own sizer, to which the wxPanel is added.

Strictly speaking, this isn't necessary as the frame will automatically
resize the panel to fill the client area if it is the only child.

Then in the
panel, I use a wxFlexGridSizer, so that the top row can have a
constant height and the bottom row be set growable.

wxFlexGridSizer is probably overkill as this can also be done in a
wxBoxSizer, but either way it is fine.

···

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

I tried using a combination of nested wxBoxSizers with horizontal and
vertical layouts without success. I even tried doing the layout using
wxDesigner, where I came close, but I couldn't save the source and it

never

worked quite right, perhaps because I didn't use spacers between the

items?!

That's the key. Here's an alternative to Donnal's solution that uses just
box sizers:

        sizer1 = wxBoxSizer(wxVERTICAL)
        sizer2 = wxBoxSizer(wxHORIZONTAL)
        self.hideIdle = wxCheckBox(self, -1, 'Hide idle',
                                   wxDefaultPosition,
                                   wxDefaultSize, wxNO_BORDER)
        self.hideIdle.SetValue(true)
        sizer2.Add(self.hideIdle, 0, wxALL, 5)
        sizer2.Add(5, 5, 1) # spacer

        self.hideUnused = wxCheckBox(self, -1, 'Hide unused',
                                     wxDefaultPosition,
                                     wxDefaultSize, wxNO_BORDER)
        self.hideUnused.SetValue(true)
        sizer2.Add(self.hideUnused, 0, wxALL, 5)

        sizer1.Add(sizer2, 0, wxEXPAND)
        self.msgHistory = wxTextCtrl(self, -1, '',
                                     wxDefaultPosition,
                                     wxSize(50,100),
                                     style=wxTE_MULTILINE |
                                     wxTE_READONLY)
        sizer1.Add(self.msgHistory, 1, wxEXPAND)
        sizer1.Fit(self)
        sizer1.SetSizeHints(self)
        self.SetSizer(sizer1)
        self.SetAutoLayout(true)
        self.Layout()

> Then in the
> panel, I use a wxFlexGridSizer, so that the top row can have a
> constant height and the bottom row be set growable.

wxFlexGridSizer is probably overkill as this can also be done in a
wxBoxSizer, but either way it is fine.

That is where I originally had problems. Can you provide any source or let
me know what nesting of wxBoxSizers will give the same result as the
wxFlexGridSizer source Donnal provided?

ka

Here's my variation on Robin's solution that I just checked into the
PythonCardPrototype cvs. I decided to continue to use a wxPanel rather than
simply changing the background frame color since all the backgrounds in
PythonCard sit on a wxPanel.

Using a panel requires a number of changes from Robin's original source
(just compare the two), so most of the places where Robin referenced self, I
referenced panel instead. In order for the window to have a minimum size
enforced by the sizer, the following line must stay the same:
  sizer1.SetSizeHints(self)

I also made some minor tweaks to the spacing. For some reason, the right
checkbox gets extra padding, even when I just use wxLEFT | wxBOTTOM.

Now I'm off to see what other trouble I can get into in sizer land.

Thanks Robin and Donnal,

ka

···

---

class MessageWatcher( wxMiniFrame, EventListener) :
    def __init__(self, parent, ID, title, pos, size, parentApp ):
        wxMiniFrame.__init__(self, parent, ID, title, pos, size,
                             wxDEFAULT_FRAME_STYLE | wxTINY_CAPTION_HORIZ)
        panel = wxPanel(self, -1)

        self.parentApp = parentApp

        EVT_CLOSE(self, self.onCloseMe)

        sizer1 = wxBoxSizer(wxVERTICAL)
        sizer2 = wxBoxSizer(wxHORIZONTAL)

        self.hideIdle = wxCheckBox(panel, -1, 'Hide idle',
                                   wxDefaultPosition, wxDefaultSize,
                                   wxNO_BORDER)
        self.hideIdle.SetValue(true)

        sizer2.Add(self.hideIdle, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5)
        sizer2.Add(5, 5, 1) # spacer

        self.hideUnused = wxCheckBox(panel, -1, 'Hide unused',
                                     wxDefaultPosition, wxDefaultSize,
                                     wxNO_BORDER)
        self.hideUnused.SetValue(true)

        sizer2.Add(self.hideUnused, 0, wxLEFT | wxBOTTOM, 5)
        sizer1.Add(sizer2, 0, wxEXPAND)

        self.msgHistory = wxTextCtrl(panel, -1, '',
                                     wxDefaultPosition, wxDefaultSize,
                                     style=wxTE_MULTILINE | wxTE_READONLY)
        f = wxFont(9, wxSWISS, wxNORMAL, wxNORMAL)
        self.msgHistory.SetFont(f)

        sizer1.Add(self.msgHistory, 1, wxEXPAND)
        sizer1.Fit(panel)
        sizer1.SetSizeHints(self)
        panel.SetSizer(sizer1)
        panel.SetAutoLayout(true)
        panel.Layout()

        EventQueue().addListener( self )

-----Original Message-----
From: wxpython-users-admin@lists.wxwindows.org
[mailto:wxpython-users-admin@lists.wxwindows.org]On Behalf Of Robin Dunn
Sent: Monday, September 10, 2001 8:45 AM
To: wxpython-users@lists.wxwindows.org
Subject: Re: [wxPython] Message Watcher sizer help

> I tried using a combination of nested wxBoxSizers with horizontal and
> vertical layouts without success. I even tried doing the layout using
> wxDesigner, where I came close, but I couldn't save the source and it
never
> worked quite right, perhaps because I didn't use spacers between the
items?!

That's the key. Here's an alternative to Donnal's solution that uses just
box sizers:

        sizer1 = wxBoxSizer(wxVERTICAL)
        sizer2 = wxBoxSizer(wxHORIZONTAL)
        self.hideIdle = wxCheckBox(self, -1, 'Hide idle',
                                   wxDefaultPosition,
                                   wxDefaultSize, wxNO_BORDER)
        self.hideIdle.SetValue(true)
        sizer2.Add(self.hideIdle, 0, wxALL, 5)
        sizer2.Add(5, 5, 1) # spacer

        self.hideUnused = wxCheckBox(self, -1, 'Hide unused',
                                     wxDefaultPosition,
                                     wxDefaultSize, wxNO_BORDER)
        self.hideUnused.SetValue(true)
        sizer2.Add(self.hideUnused, 0, wxALL, 5)

        sizer1.Add(sizer2, 0, wxEXPAND)
        self.msgHistory = wxTextCtrl(self, -1, '',
                                     wxDefaultPosition,
                                     wxSize(50,100),
                                     style=wxTE_MULTILINE |
                                     wxTE_READONLY)
        sizer1.Add(self.msgHistory, 1, wxEXPAND)
        sizer1.Fit(self)
        sizer1.SetSizeHints(self)
        self.SetSizer(sizer1)
        self.SetAutoLayout(true)
        self.Layout()

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwindows.org
http://lists.wxwindows.org/mailman/listinfo/wxpython-users

> Then in the
> panel, I use a wxFlexGridSizer, so that the top row can have a
> constant height and the bottom row be set growable.

wxFlexGridSizer is probably overkill as this can also be done in
a wxBoxSizer, but either way it is fine.

Yes, I can see that now. The first time I tried this with
wxBoxSixer I set one of the expandable flags incorrectly.

> Second, the wxFrame
> has its own sizer, to which the wxPanel is added.

Strictly speaking, this isn't necessary as the frame will
automatically resize the panel to fill the client area if
it is the only child.

My primary interest in Kevin's original question was in defining
one or more subclasses of wxPanel with sizers that can be used in
other windows such as other panels, notebooks, dialogs and frames.
On my first attempt it did not seem to work properly without
putting the panel in its own sizer, but adding

        sizer1.Fit(parent)
        sizer1.SetSizeHints(parent)

to the panel did the trick. Of course if one were to put several
panels together to make a composite, one would just add them to a
sizer as I did originally.

···

--- Robin Dunn <robin@alldunn.com> wrote:

================================================================
from wxPython.wx import *

class MessageWatcher(wxFrame) :
    def __init__(self, parent, ID, title, pos, size):
        wxFrame.__init__(self, parent, ID, title, pos, size)
        item1 = PanelA(self, -1)

class PanelA(wxPanel):
    def __init__(self, parent, id):
        wxPanel.__init__(self, parent, id)
        sizer1 = wxBoxSizer(wxVERTICAL)
        sizer2 = wxBoxSizer(wxHORIZONTAL)
        self.hideIdle = wxCheckBox(self, -1, 'Hide idle')
        sizer2.AddWindow(self.hideIdle, 0, wxALL, 5)
        sizer2.Add(5, 5, 1)
        self.hideUnused = wxCheckBox(self, -1, 'Hide unused')
        sizer2.AddWindow(self.hideUnused, 0, wxALL, 5)
        sizer1.AddSizer(sizer2, 0, wxEXPAND)
        self.msgHistory = wxTextCtrl(self, -1, '',
                                     wxDefaultPosition,
                                     wxSize(50,100),
                                     style=wxTE_MULTILINE |
                                     wxTE_READONLY)
        sizer1.AddWindow(self.msgHistory, 1, wxEXPAND)
        sizer1.Fit(parent)
        sizer1.SetSizeHints(parent)
        self.SetSizer(sizer1)
        self.SetAutoLayout(true)
        self.Layout()

class App(wxApp):
    def OnInit(self):
        frame = MessageWatcher(None, -1, 'Message Watcher',
                               wxDefaultPosition, wxDefaultSize)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = App()
app.MainLoop()

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

__________________________________________________
Do You Yahoo!?
Get email alerts & NEW webcam video instant messaging with Yahoo! Messenger