Search code examples
pythonwxpythoncustom-controlswidgetsizer

wxPython: wx.PyControl layout problem when it is a child of a wx.Panel


This is a continuation from this question:
wxPython: Can a wx.PyControl contain a wx.Sizer?

The main topic here is using a wx.Sizer inside a wx.PyControl. I had problems Fit()ting my CustomWidget around its child widgets. That problem was solved by calling Layout() after Fit().

However, as far as I have experienced, the solution only works when the CustomWidget is a direct child of a wx.Frame. It breaks down when it becomes a child of a wx.Panel.

EDIT: Using the code below, the CustomWidget doesn't resize correctly to fit its children. I observed that this only happens when the CustomWidget (as a subclass of wx.PyControl) is a child of a wx.Panel; otherwise, if it is a direct child of a wx.Frame, it Fit()s perfectly.

Here is the code:

import wx

class Frame(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self, parent=None)
    panel = Panel(parent=self)
    custom = CustomWidget(parent=panel)
    self.Show()

class Panel(wx.Panel):
  def __init__(self, parent):
    wx.Panel.__init__(self, parent=parent)
    self.SetSize(parent.GetClientSize())

class CustomWidget(wx.PyControl):
  def __init__(self, parent):
    wx.PyControl.__init__(self, parent=parent)

    # Create the sizer and make it work for the CustomWidget        
    sizer = wx.GridBagSizer()
    self.SetSizer(sizer)

    # Create the CustomWidget's children
    text = wx.TextCtrl(parent=self)
    spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)

    # Add the children to the sizer        
    sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
    sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)

    # Make sure that CustomWidget will auto-Layout() upon resize
    self.Bind(wx.EVT_SIZE, self.OnSize)
    self.Fit()

  def OnSize(self, event):
    self.Layout()

app = wx.App(False)
frame = Frame()
app.MainLoop()

Solution

  • .SetSizerAndFit(sizer) does the job. I'm not sure why a .SetSizer(sizer) then a .Fit() won't work. Any ideas?

    import wx
    
    class Frame(wx.Frame):
      def __init__(self):
        wx.Frame.__init__(self, parent=None)
        panel = Panel(parent=self)
        custom = CustomWidget(parent=panel)
        self.Show()
    
    class Panel(wx.Panel):
      def __init__(self, parent):
        wx.Panel.__init__(self, parent=parent)
        self.SetSize(parent.GetClientSize())
    
    class CustomWidget(wx.PyControl):
      def __init__(self, parent):
        wx.PyControl.__init__(self, parent=parent)
    
        # Create the sizer and make it work for the CustomWidget        
        sizer = wx.GridBagSizer()
        self.SetSizer(sizer)
    
        # Create the CustomWidget's children
        text = wx.TextCtrl(parent=self)
        spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
    
        # Add the children to the sizer        
        sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
        sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
    
        # Set sizer and fit, then layout
        self.SetSizerAndFit(sizer)
        self.Layout()
    
      # ------------------------------------------------------------
      #  # Make sure that CustomWidget will auto-Layout() upon resize
      #  self.Bind(wx.EVT_SIZE, self.OnSize)
      #  self.Fit()
      #  
      #def OnSize(self, event):
      #  self.Layout()
      # ------------------------------------------------------------    
    
    app = wx.App(False)
    frame = Frame()
    app.MainLoop()