Search code examples
wxpython

Why sizer in wxPython not work when I bind size_event to a handler function?


import wx


class MyFrame(wx.Frame):
    def __init__(self, parent):
        self.parent = parent
        super(MyFrame, self).__init__(parent, -1, 'Test')

        # create a base panel
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour('blue')
        vbox = wx.BoxSizer(wx.VERTICAL)

        # create a sub-panel 1.
        self.panel_1 = wx.Panel(self.panel, -1)
        self.panel_1.SetBackgroundColour('yellow')
        vbox.Add(self.panel_1, 1, wx.EXPAND)

        # create a sub-panel 2.
        self.panel_2 = wx.Panel(self.panel, -1)
        self.panel_2.SetBackgroundColour('pink')
        vbox.Add(self.panel_2, 1, wx.EXPAND)

        # This line of code cause the problem!
        self.panel.Bind(wx.EVT_SIZE, self._on_paint)

        self.panel.SetSizer(vbox)

        self.Show()

    def _on_paint(self, e):
        pass


app = wx.App()
frame = MyFrame(None)
app.MainLoop()

The script above don't produce the ideal output where two sub-panel should be equal in size and occupy all of the frame together.

The ideal output can be attained by delete:

self.panel.Bind(wx.EVT_SIZE, self._on_paint)

I also have tested that the script work properly if it is wx.EVT_PAINT rather than wx.EVT_SIZE.

So, why the line above cause sizer not work properly?


Solution

  • Because the default EVT_SIZE handler in the base class is where the automatic layout using the sizer is performed. By intercepting the EVT_SIZE event with your own handler you are preventing that default functionality.

    You can either call e.Skip() in your handler so the event processing system will continue looking for matching event handlers after yours is done, or you can add code like the following to your handler so the layout algorithm will still be performed:

      window = e.GetEventObject()
      if window.GetAutoLayout():
          window.Layout()