Multiple panels in a frame

Hello all!

I am pretty new to python and wxpython. I have some issues and looking for some pointers. What I am trying to do is have a single frame app, that we use panels and buttons to navigate through. I am unsure of the proper way to access (hide/show) the panels, and that is where I am stuck. I have it somewhat working using the Panel Switching Tutorial but I was trying to stay away from menus and sizers if possible since the layout will be pretty specific at the moment.

The flow would just be this:

MainFrame will create the panels and initially hide most of them (or should they be created when needed?), showing only the Start panel.

The Start panel will eventually have multiple buttons that lead to other panels that will do something.

Thanks!

So a little snippet, and my problem being what I should put in the OnClick method to get to the other panel:

class Start(wx.Panel):

#Will change to using a background and bitmap buttons

def init(self, parent):

wx.Panel.init(self, parent=parent, size=(500,500))

if DEBUG:

print “In Start init”

testBtn = wx.Button(self,label=“Start Button”)

self.Bind(wx.EVT_BUTTON, self.OnClick, testBtn)

#self.Bind(wx.EVT_BUTTON, self.GoBack)

def OnClick(self, event):

if DEBUG:

print "Start Button Clicked"

#Want to show panel_one now in the frame.

self.Hide()

#self.panel_one.Show()

#panel_one.Show()

class MainFrame(wx.Frame):

def init(self):

wx.Frame.init(self, None, wx.ID_ANY,

“Button Panel Switches”, size=(500,500))

#maybe make a panel here instead with the buttons and hide/show the panels

self.start = Start(self)

self.panel_one = PanelOne(self)

self.panel_one.Hide()

panel_test.py (1.73 KB)

Hello all!

I am pretty new to python and wxpython. I have some issues and looking for
some pointers. What I am trying to do is have a single frame app, that we
use panels and buttons to navigate through. I am unsure of the proper way to
access (hide/show) the panels, and that is where I am stuck. I have it
somewhat working using the Panel Switching Tutorial but I was trying to stay
away from menus and sizers if possible since the layout will be pretty
specific at the moment.

The flow would just be this:
MainFrame will create the panels and initially hide most of them (or should
they be created when needed?),

Probably that way is fine. Seems simplest to me.

So a little snippet, and my problem being what I should put in the OnClick
method to get to the other panel:

    def OnClick(self, event):
        if DEBUG:
            print "Start Button Clicked"
        #Want to show panel_one now in the frame.
        self.Hide()
        #self.panel_one.Show()
        #panel_one.Show()

self.Hide() should indeed hide the Start panel. But when you refer to
"self.panel_one", it's as if you are saying, "The panel_one object
that is a child of the Start panel." (The dot notation shows the
parent.child relationship). But panel_one is NOT a child of the Start
panel. It's a child of the MainFrame.

So, one thing you could do is refer to the panel_one this way: first,
you create a reference to the main frame from within the Start panel:

#In your __init__ function in the Start class:
self.main_frame = parent

Now you have a reference to the main frame within the Start panel.
Now, when you want to refer to panel_one and Show() it, you could do
this:

self.main_frame.panel_one.Show()

If you are several levels down a hierarchy of nested objects, this
approach gets awkward*. Therefore there is a built in shortcut to
wxPython I'll mention:

(*Search "Law of Demeter"; thanks, Chris Barker!)

main_frame = wx.GetTopLevelParent(self) #where self can be any window, I think

So then you're just back to
main_frame.panel_one.Show()

Does that help?

···

On Mon, Jun 17, 2013 at 8:03 PM, Chris Gatehouse <chrisgatehouse@gmail.com> wrote:

Oh yes, that helps immensely, Thanks! It is working for now. Thank you for the link and the mention of the GetTopLevelParent, that will come in handy since they will end up getting nested a bit more.

-Chris

···

On Monday, June 17, 2013 8:57:04 PM UTC-7, Che M wrote:

On Mon, Jun 17, 2013 at 8:03 PM, Chris Gatehouse > > chrisga...@gmail.com wrote:

Hello all!

I am pretty new to python and wxpython. I have some issues and looking for

some pointers. What I am trying to do is have a single frame app, that we

use panels and buttons to navigate through. I am unsure of the proper way to

access (hide/show) the panels, and that is where I am stuck. I have it

somewhat working using the Panel Switching Tutorial but I was trying to stay

away from menus and sizers if possible since the layout will be pretty

specific at the moment.

The flow would just be this:

MainFrame will create the panels and initially hide most of them (or should

they be created when needed?),

Probably that way is fine. Seems simplest to me.

So a little snippet, and my problem being what I should put in the OnClick

method to get to the other panel:

def OnClick(self, event):
    if DEBUG:
        print "Start Button Clicked"
    #Want to show panel_one now in the frame.
    self.Hide()
    #self.panel_one.Show()
    #panel_one.Show()

self.Hide() should indeed hide the Start panel. But when you refer to

“self.panel_one”, it’s as if you are saying, "The panel_one object

that is a child of the Start panel." (The dot notation shows the

parent.child relationship). But panel_one is NOT a child of the Start

panel. It’s a child of the MainFrame.

So, one thing you could do is refer to the panel_one this way: first,

you create a reference to the main frame from within the Start panel:

#In your init function in the Start class:

self.main_frame = parent

Now you have a reference to the main frame within the Start panel.

Now, when you want to refer to panel_one and Show() it, you could do

this:

self.main_frame.panel_one.Show()

If you are several levels down a hierarchy of nested objects, this

approach gets awkward*. Therefore there is a built in shortcut to

wxPython I’ll mention:

(*Search “Law of Demeter”; thanks, Chris Barker!)

main_frame = wx.GetTopLevelParent(self) #where self can be any window, I think

So then you’re just back to

main_frame.panel_one.Show()

Does that help?

Chris Gatehouse wrote:

Oh yes, that helps immensely, Thanks! It is working for now. Thank
you for the link and the mention of the GetTopLevelParent, that will
come in handy since they will end up getting nested a bit more.

Users can get surprised when a dialog reconfigures itself while they are
using it. You might consider whether a wx.Notebook or a Wizard control
would serve you better.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

I am pretty new to python and wxpython. I have some issues and looking for
some pointers. What I am trying to do is have a single frame app, that we
use panels and buttons to navigate through. I am unsure of the proper way to
access (hide/show) the panels, and that is where I am stuck. I have it
somewhat working using the Panel Switching Tutorial but I was trying to stay
away from menus and sizers if possible since the layout will be pretty
specific at the moment.

a) you really do want to use sizers -- at least if you want any
cross-platform or multi-lingual, or
work-well-when-user-changes-system-font, or have it be re-sizable, or
.....

But you can still do exactly what that tutorial does without sizers or
menus -- it's really very straightforward -- you simply call Hide()
and Show() on the relevant panels... see the onSwitchPanels method
(you won't need the Layout ir everything is statically sized..)

The flow would just be this:
MainFrame will create the panels and initially hide most of them (or should
they be created when needed?),

If there are many, many of them, and they won't all be typically used,
then I'd probably create on the fly. otherwise, why not make 'em all
up front. -- much be easier to calculate sizes, that way, too.

The Start panel will eventually have multiple buttons that lead to other
panels that will do something.

It would probably be easier to have the buttons that navigate between
panels be outside the panels that you are switching, but other than
that, you've got it.

So a little snippet, and my problem being what I should put in the OnClick
method to get to the other panel:

class Start(wx.Panel):
    #Will change to using a background and bitmap buttons
    def __init__(self, parent):
        wx.Panel.__init__(self, parent=parent, size=(500,500))
        if DEBUG:
            print "In Start init"

        testBtn = wx.Button(self,label="Start Button")
        self.Bind(wx.EVT_BUTTON, self.OnClick, testBtn)
        #self.Bind(wx.EVT_BUTTON, self.GoBack)

    def OnClick(self, event):
        if DEBUG:
            print "Start Button Clicked"
        #Want to show panel_one now in the frame.
        self.Hide()
        #self.panel_one.Show()

this is it -- you just need a way to have a reference to panel_one
here. I'd tend to keep all than managed in the frame (or a
panel_manager that isn't the frame...), then here, you'd have a call
like:

self.panel_manager.show("panel_name_or_id")

when you create the panels, you can give them a reference ot the panel_manager:

class ManagedPanel(wx.Panel):
     #Will change to using a background and bitmap buttons
     def __init__(self, panel_manager, *args, **kwargs):
         wx.Panel.__init__(self, *args, **kwargs)
         self.panel_manager = panel_manager

HTH,
-Chris

···

On Mon, Jun 17, 2013 at 5:03 PM, Chris Gatehouse <chrisgatehouse@gmail.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Now, when you want to refer to panel_one and Show() it, you could do
this:

self.main_frame.panel_one.Show()

If you are several levels down a hierarchy of nested objects, this
approach gets awkward*.

indeed.

main_frame = wx.GetTopLevelParent(self) #where self can be any window, I think

So then you're just back to
main_frame.panel_one.Show()

I wouldn't do that -- it then couples your code more than you need --
does the management of the panels necessarily have to be in the top
level parent? maybe in future re-factoring, you'll want to put the
panels on another panel, for instance.

So I'd pass a reference in to a panel_manger to the panels, even if
that is the Frame in the first iteration.

-Chris

···

On Mon, Jun 17, 2013 at 8:57 PM, C M <cmpython@gmail.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

The “panel manager” approach I like too. It’s simple and effective in non-complex projects. . Alternative approaches for apps that often get refactored or are later often upgraded with new features:

  1. For complex panel progressions try pubsub or use custom events. This is complex.

Instead of opening a “Panel8” by “Button1” on “Panel7” in “Button1”'s wx.EVT_BUTTON event handler onButton(self,event)

with a line like wx.GetApp().mainframe.PanelB.Show()

instead send a custom event named whatever, like MyEVT_SHOW_PANELB and in something like mainframe.onShowPanel(name) or PanelB.onShow() mehod (ie event handler) hide other panels.

OR

app == wx.App()

app.panels = {}

then where ever you create a relavant panel:

newpanel = MyPanel( aparent, name=“2ndPanel”)

wx.GetApp().panels[newpanel.GetName()] = newpanel

later you can do:

for name, panel in wx.GetApp().panels.items():

if name == “2ndPanel”: panel.Show()

else: panel.Hide()

Also instead of hiding the current panel and showing the next panel it might be more flexible

if you hide ALL panels and then Show() only those panel(s) that are currently relavent each time.

You might like this approach if you find yourself hitting bugs hard to trace; say when you copy

code from one panel to other (like widget id conflicts) say for a button opens say PanelHello

and that button is on several different panels.

This might be helpful when you have possible non-linear panel presentation;

ie. the “HowBig” panel may not always come after the “HowOften” panel but may come after

the “Panel7” and “JustFinishing” panels too (yes those are nonsensical panel names.)

···

On Tue, Jun 18, 2013 at 12:45 PM, Chris Barker - NOAA Federal chris.barker@noaa.gov wrote:

On Mon, Jun 17, 2013 at 8:57 PM, C M cmpython@gmail.com wrote:

Now, when you want to refer to panel_one and Show() it, you could do

this:

self.main_frame.panel_one.Show()

If you are several levels down a hierarchy of nested objects, this

approach gets awkward*.

indeed.

main_frame = wx.GetTopLevelParent(self) #where self can be any window, I think

So then you’re just back to

main_frame.panel_one.Show()

I wouldn’t do that – it then couples your code more than you need –

does the management of the panels necessarily have to be in the top

level parent? maybe in future re-factoring, you’ll want to put the

panels on another panel, for instance.

So I’d pass a reference in to a panel_manger to the panels, even if

that is the Frame in the first iteration.

-Chris

Christopher Barker, Ph.D.

Oceanographer

Emergency Response Division

NOAA/NOS/OR&R (206) 526-6959 voice

7600 Sand Point Way NE (206) 526-6329 fax

Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

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 wxpython-users+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.

Thank you all for the posts.

Very helpful, and given me some things to think about going forward. Have 7 panels now working together. Will look into reintroducing the use of sizers going forward though since I think I will need some better cross-platform support, and I’ll need to keep it easy to update.