wx.Python: Passing control between multiple panels

早过忘川 提交于 2019-12-31 05:25:30

问题


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


回答1:


In your code you have

def on_button_pressed(Panel,event):

    RightPanel().SetBackgroundColour("light blue")

In the definition 'Panel' should be 'self' as 'on_button_pressed' is a instance method

Then you are creating a new RightPanel instead of acces the already created instance.

I moved the bind to the parent frame so it can call methods on the other child panel. See the modified code below.

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.v_sizer.Add(self.button, 0)

        self.v_sizer.Add(self.h_sizer, 0, wx.EXPAND)
        self.SetSizer(self.v_sizer)


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)
        self.rightP = RightPanel(splitter)

        splitter.SplitVertically(leftP, self.rightP)
        splitter.SetMinimumPaneSize(20)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)

        leftP.button.Bind(wx.EVT_BUTTON, self.on_button_pressed)

        self.Layout()

    def on_button_pressed(self, event):
            self.rightP.SetBackgroundColour("light blue")
            self.Refresh()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()



回答2:


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.



来源:https://stackoverflow.com/questions/16505010/wx-python-passing-control-between-multiple-panels

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!