Custom controls - using other controls

PLATFORM:
Fedora Core 3 (Linux i686 AMD Athlon)
Python 2.3 and 2.4
wxPython, as reported by rpm -qa | grep wxPython
wxPython2.6-gtk2-unicode-2.6.3.2-fc2_py2.3

SUBJECT:
How to create custom controls using other controls - a composite control as
it were.

Hi,
I have made a few stabs at this, but have not had much luck yet. I can't
find an answer in "wxPython in action" and the one page on the wiki that
promises to help -- doesn't. Even google is barren!

I don't know if I absolutely need to, but I want to treat certain groupings
of controls on my form as units - much like an activeX control. My wish is
that the new control will emit events and take properties and all that
jazz.

I have no problem (touch wood!) adding function to an existing control, one
simply sublasses the control and continues. But a composite of many
controls is not so clear. I have tried subclassing both wx.Window and
wx.PyControl (working blindly because I can find no real descriptions of
what they are) - see attached code.

It seems that when I use a sizer the controls are not being sized.

I presume there will be more problems related to events and so forth.

Are there any resources, maybe a tutorial on this subject, I can go and
read?

Thanks,
Donn.

customctl.py (978 Bytes)

SUBJECT:
How to create custom controls using other controls - a composite control as
it were.

import wx

class Custom1(wx.PyControl):
    def __init__(self,parent):
        wx.PyControl.__init__(self,parent)
        p = wx.Panel(self)
        p.SetBackgroundColour("green")
        self.SetSize((500,500))
        b = wx.Button(p, -1, "Default Button")

After Custom1() is created, p and b are immediately garbage collected
(they include references to each other, but Python's cyclic GC takes
care of that!). If you want to keep them around, assign them to an
instance variable, perhaps self.p and self.b .

class Custom2(wx.Window):
    def __init__(self, parent):
        wx.Window.__init__(self,parent)
        p = wx.Panel(parent)
        p.SetBackgroundColour("red")

Same here, after Custom2() is created, p is garbage collected. Also,
you are creating p as a sibling of Custom2, not a child of it.

class Frame(wx.Frame):
    def __init__(self,parent,title):
        wx.Frame.__init__(self,parent,-1,title)
        p= wx.Panel(self)
        p.SetBackgroundColour("yellow")
        
        cus1 = Custom1(p)
        cus2 = Custom2(p)
        
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add(cus1,1,wx.EXPAND)
        box.Add(cus2,1,wx.EXPAND)
        p.SetSizer(box)
        box.Layout()
        
        self.Show()

Same thing here, p will be garbage collected immediately, which will
cause box and cus1 and cus2 to be garbage collected.

A "proper" implementation is included later in this email, where "proper"
means that the only sizer is in the panel of the frame. If you want
either of the panels created in Custom1 or Custom2 to be as large as
they can be, you may need to add sizers to Custom1 and Custom2.

Generally, any time you want to make a "composite control", you can
create a wx.Window (or wx.Panel if you want automatic tab navigation, a
nice grey backgound, and some other things), then lay everything out
using sizers, capture and re-post events as necessary, or even start
generating your own wx.CommandEvent derived events (they travel up the
parent heirarchy, non-CommandEvents don't).

- Josiah

import wx

class Custom1(wx.PyControl):
    def __init__(self,parent):
        wx.PyControl.__init__(self,parent)
        self.p = wx.Panel(self)
        self.p.SetBackgroundColour("green")
        self.b = wx.Button(self.p, -1, "Default Button")
        
class Custom2(wx.Window):
    def __init__(self, parent):
        wx.Window.__init__(self,parent)
        self.p = wx.Panel(self)
        self.p.SetBackgroundColour("red")

class Frame(wx.Frame):
    def __init__(self,parent,title):
        wx.Frame.__init__(self,parent,-1,title)
        self.p= wx.Panel(self)
        self.p.SetBackgroundColour("yellow")
        
        self.cus1 = Custom1(self.p)
        self.cus2 = Custom2(self.p)
        
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add(self.cus1,1,wx.EXPAND)
        box.Add(self.cus2,1,wx.EXPAND)
        self.p.SetSizer(box)
        box.Layout()
        
        self.Show()
        
App = wx.PySimpleApp()
frame = Frame(None,"custom controls")
App.MainLoop()