Search code examples
pythonwxpythoncustom-controlswidgetsizer

wxPython: Can a wx.PyControl contain a wx.Sizer?


Can a wx.PyControl contain a wx.Sizer?

Note that what I am ultimately trying to do here (spinner with float values) is already answered in another question. I am particularly interested in layouting widgets within a wx.PyControl, a skill which might prove useful if I come across a need to make my own custom widgets. I already read through CreatingCustomControls, but it didn't use sizers within the wx.PyControl subclass.

Using my code below, my CustomWidget just doesn't look right. I'm not yet doing a DoGetBestSize because I think that applies to a wx.Sizer acting on a widget. I am actually having a wx.Sizer doing its thing inside a CustomWidget.

Here is my code (without the event bindings between sub-widgets):
EDIT: Here is my corrected class code, thanks to Steven Sproat:

import wx

class CustomWidget(wx.PyControl):
  def __init__(self, parent):
    wx.PyControl.__init__(self, parent=parent, style=wx.NO_BORDER) # Style added.
    text = wx.TextCtrl(parent=self)
    spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
    sizer = wx.GridBagSizer()
    self.layout(text, spin, sizer)
    self.OnInit(text, sizer)

  def OnInit(self, text, sizer):
    text.SetValue(u"0.000")

  def layout(self, text, spin, sizer):
    self.SetSizer(sizer)
    sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
    sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
    self.Fit()
    self.Layout() # This is what I lacked. I needed to call .Layout()
    self.CenterOnParent()

Solution

  • Yes, it can. You just need to call Layout() to tell the sizer to recalculate/layout its children.

    import wx
    
    class Frame(wx.Frame):
      def __init__(self):
        wx.Frame.__init__(self, None)
        blah  = CustomWidget(self)
        self.Show(True)
    
    class CustomWidget(wx.PyControl):
      def __init__(self, parent):
        wx.PyControl.__init__(self, parent=parent)
        text = wx.TextCtrl(parent=self)
        spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
        sizer = wx.GridBagSizer()
        self.layout(text, spin, sizer)
        self.OnInit(text, sizer)
    
      def OnInit(self, text, sizer):
        text.SetValue(u"0.000")
    
      def layout(self, text, spin, sizer):
        self.SetSizer(sizer)
        sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
        sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
        self.Fit()
        self.Layout()
        self.CenterOnParent()
    
    app = wx.App()
    f = Frame()
    app.MainLoop()
    

    By the way, it would be nice in the future if you could attach a runnable sample as above :)