试图让wxPython上的面板更改另一个面板上的Te​​xtCtrl

时间:2013-04-05 03:03:12

标签: python user-interface wxpython

我正在编写一个与skype集成的聊天程序。我完成了大部分的工作,但是我在wxPython中遇到了关于Notebook控件的问题。我想在用户发送消息时在笔记本上创建一个新选项卡,我已经工作了,但我遇到的问题是如何引用选项卡面板上的Te​​xtCtrl?以下是我从在线提取的另一个项目的代码:

import wx

class Page(wx.Panel):
  def __init__(self, parent):
     wx.Panel.__init__(self, parent)
     t = wx.StaticText(self, -1, "THIS IS A PAGE OBJECT", (20,20))

class MainFrame(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self, None, title="Notebook Remove Pages Example")

    pannel  = wx.Panel(self)
    vbox    = wx.BoxSizer(wx.VERTICAL)
    hbox    = wx.BoxSizer(wx.HORIZONTAL)

    self.buttonRemove = wx.Button(pannel, id=wx.ID_ANY, label="DELETE", size=(80, 25))
    self.buttonRemove.Bind(wx.EVT_BUTTON, self.onButtonRemove)
    hbox.Add(self.buttonRemove)

    self.buttonInsert = wx.Button(pannel, id=wx.ID_ANY, label="CREATE", size=(80, 25))
    self.buttonInsert.Bind(wx.EVT_BUTTON, self.onButtonInsert)
    hbox.Add(self.buttonInsert)

    self.buttonMessage = wx.Button(pannel, id=wx.ID_ANY, label="Message", size=(80, 25))
    self.buttonMessage.Bind(wx.EVT_BUTTON, self.onButtonMessage)
    hbox.Add(self.buttonList)

    vbox.Add(hbox)

    self.Notebook3 = wx.Notebook(pannel)
    vbox.Add(self.Notebook3, 2, flag=wx.EXPAND)

    pannel.SetSizer(vbox)

    self.pageCounter = 0
    self.addPage()

def addPage(self):
    self.pageCounter += 1
    page      = Page(self.Notebook3)
    pageTitle = "Page: {0}".format(str(self.pageCounter))
    self.Notebook3.AddPage(page, pageTitle)

def onButtonRemove(self, event):   
    page_to_delete = self.Notebook3.GetSelection()
    self.Notebook3.DeletePage(page_to_delete)

def onButtonInsert(self, event):   
    self.addPage()

def onButtonMessage(self, event):

    self.Notebook3.StaticText(0).AppendText("Yeah right. Like this works")

if __name__ == "__main__":
   app = wx.App()
   MainFrame().Show()
   app.MainLoop()

我似乎无法将它整合在一起。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:1)

在您的类页面中,您创建了一个控件,但只将其存储在局部变量中,您需要使用self将其存储为可以从页面实例访问的实例变量。

在你的onButtonMessage方法中,你要求笔记本找到它没有的静态文本,笔记本包含页面,你也在调用AppendText,静态文本没有这个方法。

要修复此代码,您需要 将类Page更改为具有textctrl并将其存储为实例变量。 更改方法onButtonMessage以查找当前页面,然后访问其textcrtl以附加文本。

这是您修改过的代码,我也做了一些布局调整

import wx


class Page(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.textCtrl = wx.TextCtrl(self, -1, "THIS IS A PAGE OBJECT ",
                                    style=wx.TE_MULTILINE | wx.BORDER_NONE)
        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(self.textCtrl, 1, wx.EXPAND)
        self.SetSizer(vbox)


class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="Notebook Remove Pages Example")

        pannel = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        self.buttonRemove = wx.Button(pannel, id=-1, label="DELETE")
        self.buttonRemove.Bind(wx.EVT_BUTTON, self.onButtonRemove)
        hbox.Add(self.buttonRemove)

        self.buttonInsert = wx.Button(pannel, id=-1, label="CREATE")
        self.buttonInsert.Bind(wx.EVT_BUTTON, self.onButtonInsert)
        hbox.Add(self.buttonInsert)

        self.buttonMessage = wx.Button(pannel, id=-1, label="Message")
        self.buttonMessage.Bind(wx.EVT_BUTTON, self.onButtonMessage)
        hbox.Add(self.buttonMessage)

        vbox.Add(hbox, 0, wx.ALL, 7)

        self.notebook3 = wx.Notebook(pannel)
        vbox.Add(self.notebook3, 1, wx.EXPAND | wx.ALL, 7)

        pannel.SetSizer(vbox)

        self.pageCounter = 0
        self.addPage()

    def addPage(self):
        self.pageCounter += 1
        page = Page(self.notebook3)
        pageTitle = "Page: {0}".format(str(self.pageCounter))
        self.notebook3.AddPage(page, pageTitle)

    def onButtonRemove(self, event):
        page_to_delete = self.notebook3.GetSelection()
        self.notebook3.DeletePage(page_to_delete)

    def onButtonInsert(self, event):
        self.addPage()

    def onButtonMessage(self, event):
        page = self.notebook3.GetCurrentPage()
        page.textCtrl.AppendText("Yeah this works ")

if __name__ == "__main__":
    app = wx.App()
    MainFrame().Show()
    app.MainLoop()

答案 1 :(得分:1)

<> Yoriz的答案很好,但在这些情况下你需要非常小心,不要违反encapsulationabstraction

说到封装,我个人的经验法则是我的任何框架/面板/控件/对话框等。只允许调用一级别的函数。也就是说,面板可以从其父级和直接子级调用函数。在他们的解决方案中,Yoriz称两个级别的函数;在AppendText()上调用page.textCtrl

def onButtonMessage(self, event):
    page = self.notebook3.GetCurrentPage()
    page.textCtrl.AppendText("Yeah this works ")

问题是MainFrame正在调用它无法立即控制的对象上的函数。这可以通过在Page中创建一些包装函数来轻松解决:

class Page(wx.Panel):
    ...

    def AppendText(text):
        self.textCtrl.AppendText(text)

并在MainFrame中调用它:

class MainFrame(wx.Frame):
    def onButtonMessage(self, event):
        page = self.notebook3.GetCurrentPage()
        page.AppendText("Yeah this works ")

这也有问题。为了促进代码重用,我们希望我们的设计尽可能抽象,尽可能少dependenciesMainFrame {em}依赖依赖现有notebook3对象(在Yoriz的答案中)或textCtrl函数(在我上面的建议中)和如果不是这样,将会产生错误。如果您尝试在其他项目中重用AppendText(),则会产生困难。

有几种方法可以减少这些类型的依赖关系,但我个人最喜欢的是wxPython的pubsub library(你可以找到更详细的教程here)。当在一个面板中按下按钮时,您可以使用MainFrame发送消息,然后可以由另一个可以正确处理它的面板接收。您甚至可以包含参数(在您的情况下,就像设置pub.sendMessage()的文本一样)。这在概念上非常类似于wxPython已经处理按钮按下的方式,只是将“message”替换为“event”。

使用pubsub,textCtrl无需了解MainFrame。哎呀,workbook3pannel可以在不知道彼此存在的情况下进行交流;他们只需要知道要发送/订阅的消息(我建议将消息​​声明为常量)。这使您的所有组件更加灵活和可重用。

在代码中,它看起来像这样:

workbook3

显然,您提供给我们的示例代码非常简单,因此在这种特殊情况下您可以轻松地说使用pubsub获得的优势并不值得。但是,如果import wx from wx.lib.pubsub import setupkwargs #this line not required in wxPython2.9. #See documentation for more detail from wx.lib.pubsub import pub #This message requires the argument "text" MSG_CHANGE_TEXT = "change.text" class Page(wx.Panel): def __init__(self, parent): self.textCtrl = wx.TextCtrl(self, -1, "THIS IS A PAGE OBJECT ", style=wx.TE_MULTILINE | wx.BORDER_NONE) ... pub.subscribe(self.onChangeText, MSG_CHANGE_TEXT) def onChangeText(self, text): self.textCtrl.AppendText(text) class MainFrame(wx.Frame): ... def onButtonMessage(self, event): pub.sendMessage(MSG_CHANGE_TEXT, text="Yeah this works ") pannel没有共享同一个父母,该怎么办?在这种情况下,将workbook3的实例传递给workbook3并且在大量类中需要很多依赖项是非常困难的。在这种情况下,pubsub提供了一个简单,简单,干净的解决方案。