2013-04-05 76 views
1

我以书面形式与Skype整合了聊天程序的进程上TextCtrl。我完成了大部分的工作,但是我在wxPython中的Notebook控制中遇到了问题。我想在用户发送一条消息时在笔记本上创建一个新选项卡,但我遇到的问题是如何在选项卡的面板上引用TextCtrl?以下是我从网上取得的一个不同项目的代码:试图让wxPython的面板来改变另一个面板

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() 

我似乎无法把它放在一起很正确。任何帮助表示赞赏。

+0

这工作完美。非常感谢!! – dannyburrows 2013-04-05 20:01:47

回答

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 ") 

这也有问题。为了促进代码重用,我们希望我们的设计尽可能以尽可能最少的dependencies抽象出来。 MainFrame依赖notebook3notebook3存在和有一个textCtrl对象(在Yoriz的答案)或AppendText()函数(在我的建议上面),并将创建一个错误,如果不是这种情况。如果您尝试在另一个项目中重复使用MainFrame,会产生困难。

减少这些类型的依赖有几种方法,但我个人最喜欢的是wxPython的pubsub library(你可以找到更详细的教程here)。当在一个面板被按压的按钮就可以发出利用pub.sendMessage()然后可以通过其他的面板,其能够适当地处理它被接收到的消息。你甚至可以包含参数(在你的情况下,比如设置textCtrl的文本)。这在概念上与wxPython已经处理按钮按下非常相似,只是将“message”替换为“event”。

使用pubsub,MainFrame不需要知道关于workbook3的任何内容。嗨,pannelworkbook3可以沟通,甚至不知道彼此存在;他们只需要知道发送/订阅的消息(我建议将消息​​声明为常量)。这使得您的所有组件更加灵活和可重用。

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

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 ") 

很明显,你给我们的示例代码非常简单,所以在这种特殊情况下,你可以很容易地说,通过发布订阅获得的好处是不值得的努力。但是,如果pannelworkbook3没有共享同一个父项呢?在这种情况下,将workbook3的实例传递给pannel会非常困难,并且需要对大量类进行大量的依赖。在这样的情况下,pubsub提供了一个简单,简单和干净的解决方案。

+0

我真的很喜欢pubsub,[你可以从我以前的答案中看到](http://stackoverflow.com/search?q=user%3A1369712+pubsub) – acattle 2013-04-06 12:12:14

1

在你的类页面创建一个控制,但只将其存储在一个局部变量,你需要使用自己将其保存为可以从页面实例访问实例变量。

在你的方法onButtonMessage你问笔记本的静态文本,它没有一个,笔记本包含页面,你也调用AppendText哪个statictext没有这种方法。

为了解决这个问题,你需要 更改类页有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()