我正在编写一个与skype集成的聊天程序。我完成了大部分的工作,但是我在wxPython中遇到了关于Notebook控件的问题。我想在用户发送消息时在笔记本上创建一个新选项卡,我已经工作了,但我遇到的问题是如何引用选项卡面板上的TextCtrl?以下是我从在线提取的另一个项目的代码:
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 :(得分: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称两个级别的函数;在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
{em}依赖依赖现有notebook3
对象(在Yoriz的答案中)或textCtrl
函数(在我上面的建议中)和如果不是这样,将会产生错误。如果您尝试在其他项目中重用AppendText()
,则会产生困难。
有几种方法可以减少这些类型的依赖关系,但我个人最喜欢的是wxPython的pubsub library(你可以找到更详细的教程here)。当在一个面板中按下按钮时,您可以使用MainFrame
发送消息,然后可以由另一个可以正确处理它的面板接收。您甚至可以包含参数(在您的情况下,就像设置pub.sendMessage()
的文本一样)。这在概念上非常类似于wxPython已经处理按钮按下的方式,只是将“message”替换为“event”。
使用pubsub,textCtrl
无需了解MainFrame
。哎呀,workbook3
和pannel
可以在不知道彼此存在的情况下进行交流;他们只需要知道要发送/订阅的消息(我建议将消息声明为常量)。这使您的所有组件更加灵活和可重用。
在代码中,它看起来像这样:
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提供了一个简单,简单,干净的解决方案。