wxpython - 在外部文件中绑定事件
我正在尝试将一个图形界面(GUI)文件中的事件绑定到另一个文件中的代码(实际上是“前端”和“后端”)。我可以在同一个文件中让前端和后端正常工作,但当我试图把它们分到不同的文件时,就遇到了问题,后端无法识别前端的一些部分(比如标签、按钮等)。
也就是说,我需要后端代码来更改标签、进行数学运算等等,这些都需要影响到图形界面。
我提供了一个简单版本的程序。除了在尝试让后端识别图形界面的部分时出现的错误,其他一切都正常。
mainfile.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
import label_changer
class foopanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=wx.ID_ANY)
box = wx.BoxSizer()
btn = wx.Button(self,1,"Press")
btn.Bind(wx.EVT_BUTTON,label_changer.change_label(self))
box.Add(btn)
self.lbl = wx.StaticText(self,1,"Foobar")
box.Add(self.lbl)
self.SetSizerAndFit(box)
class main_frame(wx.Frame):
"""Main Frame holding the main panel."""
def __init__(self,*args,**kwargs):
wx.Frame.__init__(self,*args,**kwargs)
sizer = wx.BoxSizer()
self.p = foopanel(self)
sizer.Add(self.p,1)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = main_frame(None,-1,)
app.MainLoop()
label_changer.py
def change_label(self):
self.p.lbl.SetLabel("barfoo")
我只想让它改变图形界面的标签,但使用一个外部文件。
这样做主要是为了保持代码的独立性,同时也是为了学习。
提前谢谢大家!
3 个回答
0
这个
btn.Bind(wx.EVT_BUTTON,label_changer.change_label(self))
需要变成
btn.Bind(wx.EVT_BUTTON,label_changer.change_label)
而这个
def change_label(self):
self.p.lbl.SetLabel("barfoo")
需要变成
def change_label(event):
panel = event.GetEventObject().GetParent()
panel.lbl.SetLabel("barfoo")
为了更清楚,你需要传递一个函数的引用给Bind
,这个函数会在事件发生时被调用。wx会始终将一个参数传递给这些函数——就是事件。你在回调函数中常看到的self
,是因为它们是绑定的方法。每个绑定的方法(简单来说,就是在类中定义的函数)在调用时会隐式地传递第一个参数,这个参数是对类实例的引用。所以,由于你不能像在“外部”函数中那样传统地访问这个实例,你必须通过事件对象来获取它。
还有一点,你这样做并没有真正将图形界面(gui)和逻辑分开。这是因为逻辑(在这个例子中是label_changer)需要了解图形界面,并直接对其进行操作。有一些方法可以实现更强的分离(st2053提到过其中一种),但对于一个相对较小的程序,如果你现在不想麻烦的话,简单地把代码分成多个文件,专注于完成任务就可以了。架构方面的事情可以稍后再考虑。
2
一种解决方案是修改 change_label
函数,让它接受一个参数,这个参数用来指定要改变的标签。例如:
def change_label(event, label):
label.SetLabel("barfoo")
然后,使用 lambda
来创建一个回调函数,这个回调函数会把那个参数传递进去:
btn.Bind(wx.EVT_BUTTON, label_changer,
lambda event, label=self.p.lbl: label_changer.change_label(event, label))
确保在绑定之前先定义 self.lbl
。