wxPython 101: How to Center a Widget

I see this come up from time to time where people will ask how to center a widget in a window. The solution is actually quite easy. In most cases, you just need to nest a Horizontal BoxSizer inside of a Verticel BoxSizer with some spacers. In this article, I'll show you two three different ways to accomplish this task.

wx_centered


Using Faux Spacers

The first time I learned how to do this, I was told I could use a tuple for my spacer. The syntax looks a bit odd, but it works:

import wx

########################################################################
class MainFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Center the Button")
        panel = wx.Panel(self)
        
        h_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        
        btn = wx.Button(panel, label="Centered")
        h_sizer.Add(btn, 0, wx.CENTER)
        
        main_sizer.Add((0,0), 1, wx.EXPAND)
        main_sizer.Add(h_sizer, 0, wx.CENTER)
        main_sizer.Add((0,0), 1, wx.EXPAND)
        
        panel.SetSizer(main_sizer)
        
        self.Show()
        
if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

Here we nest a horizontal sizer inside out top-level vertical sizer. But we surround the horizontal sizer with two "spacers" that happen to be tuples that have both their proportions set to 1 and the wx.EXPAND style flag set.


Using AddStretchSpacer

wxPython's sizer's include AddStretchSpacer, which is a nice convenience method that does basically the same thing as above. Let's take a look:

import wx

########################################################################
class MainFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Center the Button")
        panel = wx.Panel(self)
        
        h_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        
        btn = wx.Button(panel, label="Centered")
        h_sizer.Add(btn, 0, wx.CENTER)
        
        main_sizer.AddStretchSpacer(prop=1)
        main_sizer.Add(h_sizer, 0, wx.CENTER)
        main_sizer.AddStretchSpacer(prop=1)
        
        panel.SetSizer(main_sizer)
        
        self.Show()
        
if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

You will note that the only difference here is using the AddStretchSpacer method along with its prop parameter set to 1.


Centering Without Nesting Sizers

One of my astute readers mentioned a third way to center the widget that does not require nesting the sizers. Let's take a look:

import wx

class MainFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Center the Button")
        panel = wx.Panel(self)

        main_sizer = wx.BoxSizer(wx.VERTICAL)

        btn = wx.Button(panel, label="Centered")
        main_sizer.AddStretchSpacer()
        main_sizer.Add(btn, 0, wx.CENTER)
        main_sizer.AddStretchSpacer()

        panel.SetSizer(main_sizer)

        self.Show()
        
if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

Here we just create a vertical sizer, add a stretch spacer and then tell the button to be centered, then add another stretch spacer. The code is very similar to the previous example except that we don't use a horizontal sizer at all. Special thanks goes to Yoriz for mentioned this to me in the comments.

Copyright © 2024 Mouse Vs Python | Powered by Pythonlibrary