Search code examples
pythonuser-interfacewxpythonwxwidgets

wxPython: How to make sizer fill its parent entirely


I have a problem where BoxSizer doesn't fill its parent.

Problem screenshot

In the above screenshot I mean the sizer containing yellow and purple panels. I want this sizer and the panels to fill the entire panel in Main tab.

The only way I found to accomplish this is to SetMinSize() on the sizer to some big value. I can't set it to panel's actual size because GetSize() on the panel returns very small and definitely not real values.

Here's the relevant code:

import wx


class App(wx.Frame):
    """Main app window wrapping around everything else.
    """

    def __init__(self):
        super(App, self).__init__(None, title='TSP Visual', size=(1200, 900))
        self.init_ui()
        self.Centre()
        self.Show()

    def init_ui(self):
        # Menubar
        menu_bar = wx.MenuBar()
        file_menu = wx.Menu()
        exit_mi = file_menu.Append(wx.ID_EXIT, 'Exit', 'Exit application')
        menu_bar.Append(file_menu, 'File')
        self.SetMenuBar(menu_bar)
        # Main layout
        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        # Title
        title = wx.StaticText(panel, label='No instance loaded')
        title_font = wx.Font(wx.FontInfo(18))
        title.SetFont(title_font)
        title.SetMinSize(title.GetTextExtent(title.Label))
        sizer.Add(title, 0, wx.EXPAND | wx.ALL, 10)
        # Tabs
        notebook = wx.Notebook(panel)
        main_tab = MainTab(notebook)
        stats_tab = StatsTab(notebook)
        notebook.AddPage(main_tab, 'Main')
        notebook.AddPage(stats_tab, 'Stats')
        sizer.Add(notebook, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)

        panel.SetSizerAndFit(sizer)
        # Event bindings
        self.Bind(wx.EVT_MENU, lambda e: self.Close(), exit_mi)


class MainTab(wx.Panel):
    """Main tab of the app, solver controls and tsp view.
    """

    def __init__(self, parent):
        super(MainTab, self).__init__(parent)
        self.init_ui()

    def init_ui(self):
        # Panel sizer
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        # Solver controls and TSP view
        controls = SolverControls(self)
        controls.SetBackgroundColour('yellow')
        tsp_view = TSPView(self)
        tsp_view.SetBackgroundColour('purple')
        sizer.Add(controls, 1, wx.EXPAND)
        sizer.Add(tsp_view, 1, wx.EXPAND)
        self.SetSizerAndFit(sizer)


class StatsTab(wx.Panel):
    """Second tab, graphs and statistics
    """

    def __init__(self, parent):
        super(StatsTab, self).__init__(parent)
        self.init_ui()

    def init_ui(self):
        pass


class TSPView(wx.Panel):

    def __init__(self, parent):
        super(TSPView, self).__init__(parent)
        self.init_ui()

    def init_ui(self):
        self.SetBackgroundColour('white')


class SolverControls(wx.Panel):

    def __init__(self, parent):
        super(SolverControls, self).__init__(parent)
        self.init_ui()

    def init_ui(self):
        sizer = wx.GridBagSizer()
        text = wx.StaticText(self, label='Test text')
        sizer.Add(text, (0, 0), (1, 1), wx.ALL, 5)
        button1 = wx.Button(self, label='Button 1')
        sizer.Add(button1, (1, 0), (1, 1), wx.ALL, 5)
        button2 = wx.Button(self, label='Button 2')
        sizer.Add(button2, (2, 0), (1, 1), wx.ALL, 5)
        self.SetSizer(sizer)


if __name__ == '__main__':
    app = wx.App()
    App()
    app.MainLoop()

EDIT: I've changed my code sample so it's self contained and runnable.


Solution

  • So it turned out the problem was somehow related to i3wm window manager. Since manually resizing the window fixes the problem I came up with a solution where I SetSize() of the window after Show()ing it. My __init__() method of App looks like this:

    def __init__(self):
        super(App, self).__init__(None, title='TSP Visual')
        self.init_ui()
        self.Show()
        self.SetSize(1200, 900)
        self.Centre()