wx.Python: Passing control between multiple panels
Question: I'm a newbie to wxPython, and have researched similar questions, but can't
specifically find an answer to my question. I'm creating two panels with a
splitter. Each panel has a number of widgets. I'd like to have a widget in one
panel control some properties of the other and vice versa)

In the example, I'm trying to change the background of `RightPanel` from a
button in `LeftPanel`. I'm obviously doing something wrong as a I get an
error:

> TypeError: **init**() takes exactly 2 arguments (1 given)

Code:

    
    
    import wx
    import wx.grid as gridlib
    import  pyodbc
    
    class RightPanel(wx.Panel):
    """"""
    
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)        
    
        grid = gridlib.Grid(self)
        grid.CreateGrid(5,5)
    
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 0, wx.EXPAND)
        self.SetSizer(sizer)
    
    class LeftPanel(wx.Panel):
    """"""
    
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)  
    
        self.create_controls()
        self.SetBackgroundColour("light green")
    
    def create_controls(self):
    
        self.h_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.v_sizer = wx.BoxSizer(wx.VERTICAL)
    
        self.button = wx.Button(self, label="Press me!")
        self.button.Bind(wx.EVT_BUTTON, self.on_button_pressed)     
    
        self.v_sizer.Add(self.button, 0)
    
        self.v_sizer.Add(self.h_sizer, 0, wx.EXPAND)
        self.SetSizer(self.v_sizer)
    
    def on_button_pressed(Panel,event):
    
            RightPanel().SetBackgroundColour("light blue")
    
    class MyForm(wx.Frame):
    
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "DB Viewer",size=(350, 250))
    
        splitter = wx.SplitterWindow(self)
        leftP = LeftPanel(splitter)
        rightP = RightPanel(splitter)
    
        splitter.SplitVertically(leftP, rightP)
        splitter.SetMinimumPaneSize(20)
    
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)
    
    if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()
    

Any help greatly appreciated. Regards


Answer: A clean design can be achieve using pubsub:

    
    
    import wx
    import wx.grid as gridlib
    from wx.lib.pubsub import pub
    
    #import pyodbc
    
    class RightPanel(wx.Panel):
        """"""
    
        def __init__(self, parent):
            """Constructor"""
            wx.Panel.__init__(self, parent=parent)        
    
            grid = gridlib.Grid(self)
            grid.CreateGrid(5,5)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(grid, 0, wx.EXPAND)
            self.SetSizer(sizer)
    
            pub.subscribe(self.changeColourEvent, "MOOD_CHANGE")
    
    
        def changeColourEvent(self, value):
            self.SetBackgroundColour(value)
            self.Refresh()
    
    
    class LeftPanel(wx.Panel):
        """"""
    
        def __init__(self, parent):
            """Constructor"""
            wx.Panel.__init__(self, parent=parent)  
    
            self.create_controls()
            self.SetBackgroundColour("grey")
    
    
        def create_controls(self):
    
            self.h_sizer = wx.BoxSizer(wx.HORIZONTAL)
            self.v_sizer = wx.BoxSizer(wx.VERTICAL)
    
            self.bbutton = wx.Button(self, label="Got dem blues?!")
            self.bbutton.Bind(wx.EVT_BUTTON, self.blues_button_pressed)     
    
            self.hbutton = wx.Button(self, label="Happy happy!")
            self.hbutton.Bind(wx.EVT_BUTTON, self.happy_button_pressed)     
    
            self.v_sizer.Add(self.bbutton, 0)
            self.v_sizer.Add(self.hbutton, 0)
    
            self.v_sizer.Add(self.h_sizer, 0, wx.EXPAND)
            self.SetSizer(self.v_sizer)
    
    
        def blues_button_pressed(self,event):
            pub.sendMessage("MOOD_CHANGE", value = "blue")        
    
    
        def happy_button_pressed(self,event):
            pub.sendMessage("MOOD_CHANGE", value = "yellow")        
    
    
    class MyForm(wx.Frame):
    
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "DB Viewer",size=(350, 250))
    
            splitter = wx.SplitterWindow(self)
            leftP = LeftPanel(splitter)
            rightP = RightPanel(splitter)
    
            splitter.SplitVertically(leftP, rightP)
            splitter.SetMinimumPaneSize(20)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(splitter, 1, wx.EXPAND)
            self.SetSizer(sizer)
    
    if __name__ == "__main__":
        app = wx.App(False)
        frame = MyForm()
        frame.Show()
        app.MainLoop()
    

The advantage that this sort of approach brings is that it means that no pane
is dependent on the design of any other pane. You can see that neither MyForm
nor RightPanel needs to know whether LeftPanel is deciding that it's time to
change colour based on a button or a checkbox or any other mechanism. In this
code, MyForm cares only about instantiating two panes. It does not get tangled
up in the logic of what goes between them.

It's also readily extensible in the type of information that objects (in this
case, panes) can pass to each other.

It also allows for other elements to be added to the design that care about
the same kinds of thing (in my example case, mood changes) without impacting
the code of anything other than themself.

