在tkinter中编写一些简单的图形用户界面应用程序时,我遇到了一些小问题。假设我有自定义菜单小部件(派生自tk.menu)和自定义画布小部件(派生自tk.canvas)。
我想从菜单回调函数生成事件并在画布小部件中调用它。我需要这样做,因为它的未来,我想添加更多的小部件,应作出反应,点击位置在菜单上。
我试着那样做:
自定义菜单:
class MainMenu(tk.Menu):
def __init__(self, parent):
tk.Menu.__init__(self, parent)
self.add_comand(label='foo', self._handler)
return
def _handler(self, *args):
print('handling menu')
self.event_generate('<<abc>>')
return
自定义画布:
class CustomCanvas(tk.Canvas):
def __init__(self, parent, name=''):
tk.Canvas.__init__(self, parent)
self.bind('<<abc>>', self.on_event)
return
def on_event(self, event):
print(event)
return
当我单击菜单中的“位置”时,会正确调用“处理程序回调”并生成“事件”<;gt;,但不会调用“打开事件回调”。我试图添加when='tail'参数、add self.update()等,但没有任何结果。有人知道怎么做吗?
下面是创建自定义虚拟事件的示例代码。我创建此代码是为了模拟调用服务器,这些服务器需要很长时间才能响应数据:
在这个代码示例中,我正在创建自定义虚拟事件,在模拟服务器完成数据检索后调用这些事件。事件处理程序onVirtualEvent绑定到根级别的自定义虚拟事件。
单击按钮时,模拟服务器将在单独的执行线程中运行。我使用一个定制的decorator,TS_decorator,来创建调用模拟服务器将运行的执行线程。
我的方法真正有趣的部分是,我可以通过调用firevirtualent方法将从模拟服务器检索到的数据提供给事件处理程序。在这个方法中,我将向事件类添加一个自定义属性,该属性将保存要传输的数据。然后,我的事件处理程序将使用此自定义属性从服务器中提取数据。
虽然在概念上很简单,但是这个示例代码也减轻了在处理需要长时间执行的代码时GUI元素不更新的问题。因为所有的工作代码都是在一个单独的执行线程中执行的,所以对函数的调用会很快返回,这就允许GUI元素进行更新。请注意,我还将对myApp类的引用传递给模拟服务器,以便它们可以在数据可用时调用其FireVirtualEvent方法。
最后,我使用了Bryan的解决方案,并进行了一些改进(我希望在模块之间保持一些分隔,以便并行地开发它们)。
总体思路:
添加方法以保存特定虚拟事件的“侦听器”小部件列表
在根/应用程序设置过程中,使用自定义方法在小部件之间配置“绑定网络”;
配置绑定网络:
在小部件中绑定虚拟事件:
向“generator”小部件添加方法以保存“listener”小部件的列表:
您需要将绑定添加到获取事件的小部件。在您的例子中,您是在菜单上生成事件的,因此需要绑定到菜单。
您还可以在画布上生成事件,并将绑定保留在画布上。或者,将事件与根窗口关联,并绑定到根窗口。
tkinter本身在某些情况下使用的一种常见技术是在根窗口上生成事件,然后在根窗口上(或者对于所有具有
bind_all
的窗口)为该事件创建一个绑定。然后,单个绑定必须通过某种方式确定要影响哪个窗口(通常,例如,通过键盘焦点获取窗口)。当然,如果有方法确定哪个小部件获得绑定,那么可以在生成事件时使用该方法直接在相应的小部件上生成事件。
有关更多信息,请参见http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm,特别是文档中标题为“实例和类绑定”的部分。
相关问题 更多 >
编程相关推荐