[wxPython-users] Sizing Notebook pages in a splitter window

Josiah Carlson jcarlson at uci.edu
Mon Jan 1 11:47:30 PST 2007


(I normally don't top-post, but there is a reason here)

Using SetPosition() and SetSize() lies madness unless you know what you
are doing.  Use sizers.  Always use sizers.  I started modifying your
code, but then I stopped because I couldn't understand what you wanted
to do.  The I tried to rewrite it, but I still couldn't figure out what
you wanted to do.  It's probably just too early in the day.


Here are some pointers when using sizers...

    #define your controls...
    c1 = ...
    c2 = ...
    c3 = ...

    #create the sizers and define the layout
    sz1 = wx.BoxSizer(wx.VERTICAL)
    sz1.AddPage(c1, ...)
    sz1.AddPage(c2, ...)
    sz1.AddPage(c3, ...)

    #always remember to set your sizer
    parent_control.SetSizer(sz1)


For example:

    p = wx.Panel(frame)

    c1 = wx.StaticText(p, label="label")
    c2 = wx.TextCtrl(p)
    c3 = wx.Button(p, label="button")

    s = wx.BoxSizer(wx.HORIZONTAL)
    s.Add(c1, 0, wx.ALIGN_CENTER_VERTICAL)
    s.Add(c2, 1, wx.LEFT|wx.EXPAND, 5)
    s.Add(c3, 0, wx.LEFT|wx.EXPAND, 5)
    
    p.SetSizer(s)

    frame.sizer.Add(p, 1, wx.EXPAND)


Also note that each "page" of a wx.Splitter, wx.Notebook, or similar
control will automatically be sized according to its base size handler,
which for all controls (except for base wx.Windows) is more or less to
"make me fill up the space unless I have restricted my own size, size my
children based on my size, using my sizer".


Say, for example, that you had a notebook that you wanted to add pages
to...

    nb = wx.Notebook(p)

    w1 = wx.Window(nb);w1.SetBackgroundColour("pink")
    w2 = wx.Window(nb);w2.SetBackgroundColour("sky blue")

    nb.AddPage(w1, "pink page")
    nb.AddPage(w2, "sky blue page")

    #no sizers needed!

If you want the pages to be interesting...

    nb = wx.Notebook(p)

    #note the use of wx.Panel below!
    w1 = wx.Panel(nb);w1.SetBackgroundColour("pink")
    w2 = wx.Window(nb);w2.SetBackgroundColour("sky blue")

    nb.AddPage(w1, "pink page")
    nb.AddPage(w2, "sky blue page")

    #add sub-controls to w1!

    c1 = wx.StaticText(w1, label="label")
    c2 = wx.TextCtrl(w1)
    c3 = wx.Button(w1, label="button")

    s = wx.BoxSizer(wx.HORIZONTAL)
    s.Add(c1, 0, wx.ALIGN_CENTER_VERTICAL)
    s.Add(c2, 1, wx.LEFT|wx.EXPAND, 5)
    s.Add(c3, 0, wx.LEFT|wx.EXPAND, 5)

    s2 = wx.BoxSizer(wx.VERTICAL)
    s2.Add(s, 0, wx.ALL|wx.EXPAND, 5)

    w1.SetSizer(s2)

Note that wx.Panel offers automatic handling of sub-sizers, while
wx.Window does not.

Here's runnable code for you to see the above in action.

 - Josiah

import wx

def generate_sub(p):
    c1 = wx.StaticText(p, label="label")
    c2 = wx.TextCtrl(p)
    c3 = wx.Button(p, label="button")
    
    s = wx.BoxSizer(wx.HORIZONTAL)
    s.Add(c1, 0, wx.ALIGN_CENTER_VERTICAL)
    s.Add(c2, 1, wx.LEFT|wx.EXPAND, 5)
    s.Add(c3, 0, wx.LEFT|wx.EXPAND, 5)
    
    s2 = wx.BoxSizer(wx.VERTICAL)
    s2.Add(s, 0, wx.ALL|wx.EXPAND, 5)
    
    p.SetSizer(s2)

def generate(f):
    nb = wx.Notebook(f)
    
    w1 = wx.Panel(nb);w1.SetBackgroundColour("pink")
    w2 = wx.Window(nb);w2.SetBackgroundColour("sky blue")
    
    nb.AddPage(w1, "pink page")
    nb.AddPage(w2, "sky blue page")
    
    #add sub-controls to each, showing the window/panel incongruity!
    generate_sub(w1)
    generate_sub(w2)
    
    #used to force a size event
    f.SetSize((640,480))
    return nb

if __name__ == '__main__':
    a = wx.App(0)
    f = wx.Frame(None, title="example")
    nb = generate(f)
    f.Show(1)
    a.MainLoop()


"Edward K. Ream" <edreamleo at charter.net> wrote:
> Hello All,
> 
> I am having difficulties properly sizing notebook pages insde a splitter
> window.  I hope somebody can help.
> 
> I am using wxPython 2.8.0.1 (wxMSW, unicode, wx-assertions-on, SWIG-1.3.29)
> running on Python 2.4, on XP, all service packs installed.
> 
> To explore various options, I created a new demo called Leo in the wxPython
> demo.  So to run the following code, copy it to a file called Leo.py in the
> wxPython demo folder, and add an entry for Leo in the Recent
> Additions/Updates section in Main.py.
> 
> The code is at the end of the posting.  First I'll explain what it does and
> what I would like it to do.
> 
> 1. There are two switches in runTest called useNotebook and useSizer.  Let
> us assume that useSizer is always True.  When useNotebook is False, the code
> uses a FlexGridSizer to insert two TextCtrls with labels into the right-hand
> splitter window.  Everything works as expected: all controls are aligned
> nicely.
> 
> 2. When useNotebook is True the code creates a Notebook with two pages
> called 'Log' and 'Find'.  The Log page has a textCtrl that should fill the
> Notebook page (It does, but the page is too small).  The Find page should
> look pretty much exactly the same as when useNotebook is False: that is, it
> should contain two TextCtrls with labels that are managed by a
> FlexGridSizer.
> 
> I would like both notebook pages to fill the right-hand splitter window, but
> have found no way to do this.  The present code doesn't even show all the
> widgets that are (presumably) in the 'Find' window.  Can anyone suggest the
> solution?  Thanks!
> 
> Here is Leo.py:
> 
> # Leo test stuff for wxWidgets.
> 
> overview = """<html>Leo"""
> 
> import wx
> 
> class MySplitter(wx.SplitterWindow): ### Unchanged from the SpitterWindow
> demo.
>     def __init__(self, parent, ID, log):
>         wx.SplitterWindow.__init__(self, parent, ID,
>                                    style = wx.SP_LIVE_UPDATE
>                                    )
>         self.log = log
> 
>         self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
>         self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
> 
>     def OnSashChanged(self, evt):
>         self.log.WriteText("sash changed to %s\n" %
> str(evt.GetSashPosition()))
> 
>     def OnSashChanging(self, evt):
>         self.log.WriteText("sash changing to %s\n" %
> str(evt.GetSashPosition()))
>         # uncomment this to not allow the change
>         #evt.SetSashPosition(-1)
> 
> class TestPanel(wx.Panel):
> 
>     def __init__(self, parent, log):
>         self.log = log
>         wx.Panel.__init__(self, parent)
> 
> def makeNBPanel(parent): # Like makeColorPanel in Notebook demo.
>     p = wx.Panel(parent, -1)
>     def OnCPSize(evt,p=p):
>         p.SetPosition((0,0))
>         p.SetSize(evt.GetSize())
>     p.Bind(wx.EVT_SIZE, OnCPSize)
>     return p
> 
> def runTest(frame, nb, log):
> 
>     splitter = MySplitter(nb, -1, log)
>     p1 = wx.Window(splitter, style=wx.BORDER_SUNKEN)
>     p1.SetBackgroundColour("pink")
>     wx.StaticText(p1, -1, "Panel One", (5,5))
> 
>     p2 = wx.Window(splitter, style=wx.BORDER_SUNKEN)
>     p2.SetBackgroundColour("sky blue")
>     # wx.StaticText(p2, -1, "Panel Two", (5,5))
> 
>     splitter.SetMinimumPaneSize(20)
>     splitter.SplitVertically(p1, p2, -100)
> 
>     useNotebook = False
>     useSizer = True
> 
>     if useNotebook:
>         nbParent = wx.Panel(p2)
>         nb = wx.Notebook(nbParent,style=wx.BK_DEFAULT)
>         log = makeNBPanel(nb)
>         wx.TextCtrl(log,size=(1000,2000))
>         nb.AddPage(log,'Log')
>         p = makeNBPanel(nb)
>         nb.AddPage(p,'Find')
> 
>     else:
>         p = wx.Panel(p2, -1,
>             style = wx.TAB_TRAVERSAL | wx.CLIP_CHILDREN |
> wx.FULL_REPAINT_ON_RESIZE)
> 
>     if useSizer:
>         label1 = wx.StaticText(p,label='Find',style=wx.ALIGN_LEFT)
>         label2 = wx.StaticText(p,label='Change',style=wx.ALIGN_LEFT)
> 
>         sizer1 = wx.FlexGridSizer(2, 2, vgap=10,hgap=5)
> 
>         sizer1.Add(wx.TextCtrl(p),1,wx.EXPAND)
>         sizer1.Add(label1,0,wx.EXPAND)
>         sizer1.Add(wx.TextCtrl(p),1,wx.EXPAND)
>         sizer1.Add(label2,0,wx.EXPAND)
> 
>         if useNotebook:
>             nbParent.SetSizerAndFit(sizer1)
>             nb.SetClientSize(nbParent.GetSize())
>             # nb.SetClientSize(p2.GetSize())
>             # Notebook disappears completely.
>         else:
>             p.SetSizerAndFit(sizer1)
>             p2.SetClientSize(p.GetSize())
>     else:
>         if useNotebook:
>             nb.SetClientSize(nbParent.GetSize())
> 
>     return splitter





More information about the wxpython-users mailing list