Wxpython Sizer position

75 Views Asked by At

I have the below sample application which has a couple of simple sizers which, for some reason, are centered vertically, which I dont want (see attachment). I want the wxchoice sizer to be position at the top of the window, not in the middle vertically, even when resizing the window, it stays in that position, but I just can't find the asnwer.

enter image description here

import wx

class Mywin(wx.Frame):
    def __init__(self, parent, id, title):

        super(Mywin, self).__init__(parent, title=title)
        self.panel = wx.Panel(self)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        nm = wx.StaticBox(self.panel, -1, 'Drop List:')
        nmSizer = wx.StaticBoxSizer(nm, wx.VERTICAL)

        self.workflowList = ["choice 1", "choice 2"]
        nmbox = wx.BoxSizer(wx.HORIZONTAL)
        self.workflowChoice = wx.Choice(self.panel, choices=self.workflowList)

        self.vbox.Add(nmSizer, 0, wx.ALL | wx.EXPAND, 0)
        nmbox.Add(self.workflowChoice, 0, wx.ALL, 5)
        nmSizer.Add(nmbox, 0, wx.ALL, 5)

        self.btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.buttonGo = wx.Button(self.panel, -1, "Go")

        self.buttonClose = wx.Button(self.panel, -1, "Quit")

        self.btnSizer.Add(self.buttonGo, 0, wx.ALL, 5)
        self.btnSizer.Add(self.buttonClose, 0, wx.ALL, 5)

        self.vbox.Add(nmSizer, 0, wx.ALL | wx.CENTER | wx.TOP, 5)
        self.vbox.Add(self.btnSizer, 0, wx.ALL | wx.CENTER, 5)

        self.panel.SetSizer(self.vbox)

        self.panel.Fit()
        self.Show()

app = wx.App()
Mywin(None, -1, 'Test App ')
app.MainLoop()
2

There are 2 best solutions below

0
Rolf of Saxony On

You are adding a StaticBox to a StaticBoxSizer, so it's probably getting its knickers in a twist.

Try something along the lines of:

import wx

class Mywin(wx.Frame):
    def __init__(self, parent, id, title):

        super(Mywin, self).__init__(parent, id=id, title=title)
        self.panel = wx.Panel(self)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        nm = wx.StaticBoxSizer(wx.VERTICAL, self.panel, 'Drop List:')

        self.workflowList = ["choice 1", "choice 2"]
        self.workflowChoice = wx.Choice(self.panel, choices=self.workflowList)
        nm.Add(self.workflowChoice, 0, wx.ALL|wx.EXPAND, 5)

        self.vbox.Add(nm, 0, wx.ALL, 5) # Add the box to the sizer

        self.btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.buttonGo = wx.Button(self.panel, -1, "Go")

        self.buttonClose = wx.Button(self.panel, -1, "Quit")

        self.btnSizer.Add(self.buttonGo, 0, wx.ALL, 5)
        self.btnSizer.Add(self.buttonClose, 0, wx.ALL, 5)

        self.vbox.Add(self.btnSizer, 0, wx.ALL|wx.EXPAND, 0)

        self.panel.SetSizer(self.vbox)

        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.buttonClose.Bind(wx.EVT_BUTTON, self.OnClose)
        self.Show()

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

app = wx.App()
Mywin(None, -1, 'Test App ')
app.MainLoop()

enter image description here

0
Mace On

Firstly you program's Drop List is strangely switching positions. This is because you added nmSizer twice to self.vbox. I have commented out the first "add" and the strange behaviour has gone now.

To answer your question about keeping items at the top of the window:

wxPython use the proportion property of sizers for this.

Sizers with a high proportion value kind of push sizers with lower proportion value to the side, top, left, bottom, right, depending on the type of the sizer they are added to.

In your code I have given the sizers inside self.vbox proportion value 1.

self.vbox.Add(nmSizer, 1, wx.ALL | wx.CENTER | wx.TOP, 5)  # proportion 1
self.vbox.Add(self.btnSizer, 1, wx.ALL | wx.CENTER, 5)  # proportion 1

Next I have added a so called spacer to self.vbox and given it proportion 10.

self.vbox.Add( ( 0, 0), 10, wx.EXPAND, 5 )  # proportion 10

The value 10 of this spacer's proportion pushes the other sizers to the top. The spacer is otherwise invisible. It just 'pushes' the other sizers to the top.

The adjusted code:

import wx

class Mywin(wx.Frame):
    def __init__(self, parent, id, title):

        super(Mywin, self).__init__(parent, title=title)
        self.panel = wx.Panel(self)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        nm = wx.StaticBox(self.panel, -1, 'Drop List:')
        nmSizer = wx.StaticBoxSizer(nm, wx.VERTICAL)

        self.workflowList = ["choice 1", "choice 2"]
        nmbox = wx.BoxSizer(wx.HORIZONTAL)
        self.workflowChoice = wx.Choice(self.panel, choices=self.workflowList)

        # ADD nmSizer 1st time commented this out
        # self.vbox.Add(nmSizer, 0, wx.ALL | wx.EXPAND, 0)
        nmbox.Add(self.workflowChoice, 0, wx.ALL, 5)
        nmSizer.Add(nmbox, 1, wx.ALL, 5)  # proportion 1

        self.btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.buttonGo = wx.Button(self.panel, -1, "Go")

        self.buttonClose = wx.Button(self.panel, -1, "Quit")

        self.btnSizer.Add(self.buttonGo, 0, wx.ALL, 5)
        self.btnSizer.Add(self.buttonClose, 0, wx.ALL, 5)

        # ADD nmSizer 2nd time, KEPT THIS ONE
        self.vbox.Add(nmSizer, 1, wx.ALL | wx.CENTER | wx.TOP, 5)  # proportion 1
        self.vbox.Add(self.btnSizer, 1, wx.ALL | wx.CENTER, 5)  # proportion 1
        # add spacer
        self.vbox.Add( ( 0, 0), 10, wx.EXPAND, 5 )  # proportion 10

        self.panel.SetSizer(self.vbox)

        self.panel.Fit()
        self.Show()

app = wx.App()
Mywin(None, -1, 'Test App ')
app.MainLoop()

Using a spacer to keep objects at top.

enter image description here

Other wx object can also be used as 'pusher/filler'. If you want to use the remainder of your panel for a TextCtrl then give the created TextCtrl a high proprotion value.

import wx

class Mywin(wx.Frame):
    def __init__(self, parent, id, title):

        super(Mywin, self).__init__(parent, title=title)
        self.panel = wx.Panel(self)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        nm = wx.StaticBox(self.panel, -1, 'Drop List:')
        nmSizer = wx.StaticBoxSizer(nm, wx.VERTICAL)

        self.workflowList = ["choice 1", "choice 2"]
        nmbox = wx.BoxSizer(wx.HORIZONTAL)
        self.workflowChoice = wx.Choice(self.panel, choices=self.workflowList)

        # ADD nmSizer 1st time commented this out
        # self.vbox.Add(nmSizer, 0, wx.ALL | wx.EXPAND, 0)
        nmbox.Add(self.workflowChoice, 0, wx.ALL, 5)
        nmSizer.Add(nmbox, 1, wx.ALL, 5)  # proportion 1

        self.btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.buttonGo = wx.Button(self.panel, -1, "Go")

        self.buttonClose = wx.Button(self.panel, -1, "Quit")

        self.btnSizer.Add(self.buttonGo, 0, wx.ALL, 5)
        self.btnSizer.Add(self.buttonClose, 0, wx.ALL, 5)

        # ADD nmSizer 2nd time, KEPT THISS ONE
        self.vbox.Add(nmSizer, 1, wx.ALL | wx.CENTER | wx.TOP, 5)  # proportion 1
        self.vbox.Add(self.btnSizer, 1, wx.ALL | wx.CENTER, 5)  # proportion 1

        # add spacer not needed, the following textctrl is used for this
        # self.vbox.Add( ( 0, 0), 10, wx.EXPAND, 5 )  # proportion 10

        # add text ctrl
        self.textctrl_info = wx.TextCtrl(self.panel, wx.ID_ANY,
                                         wx.EmptyString, wx.DefaultPosition,
                                         wx.DefaultSize, wx.TE_MULTILINE)
        self.vbox.Add(self.textctrl_info, 25, wx.ALL | wx.EXPAND, 5)  # proportion 25

        self.panel.SetSizer(self.vbox)

        self.panel.Fit()
        self.Show()


app = wx.App()
Mywin(None, -1, 'Test App ')
app.MainLoop()

Using a TextCtrl to keep objects at top.

enter image description here

Want the pusher filler above the buttons? Just change the order of adding to self.vbox.

    # ADD nmSizer 2nd time, KEPT THISS ONE
    self.vbox.Add(nmSizer, 1, wx.ALL | wx.CENTER | wx.TOP, 5)  # proportion 1

    # add text ctrl
    self.textctrl_info = wx.TextCtrl(self.panel, wx.ID_ANY,
                                     wx.EmptyString, wx.DefaultPosition,
                                     wx.DefaultSize, wx.TE_MULTILINE)
    self.vbox.Add(self.textctrl_info, 25, wx.ALL | wx.EXPAND, 5)  # proportion 25

    self.vbox.Add(self.btnSizer, 1, wx.ALL | wx.CENTER, 5)  # proportion 1

enter image description here