wxPython:Notebook 似乎不适用于多重绑定
wxPython : Notebook seems not to work with multibinding
我正在尝试创建一个 wxPython 应用程序。简化我的设置,假设我有一个左面板和一个右面板。左侧面板有我的控件,它们是 sliders/buttons/etc。右侧面板包括一个笔记本,在每个选项卡中我都显示从图像数据列表中获取的视频帧。如果我不使用笔记本,一切都很好,控制事件改变了右侧面板的功能。但是,当我实现笔记本时,考虑了笔记本内每个面板和每个控件的多重绑定,我得到了一些奇怪的行为。发生的情况是每个控件似乎都有不同的父控件,因此我无法将同一 class(!!!) 内的变量从一种方法传递到另一种方法。由于问题的复杂性,我无法解释结果。下面是一个例子:
import wx
import numpy as np
def checkclass(obj, clas):
if isinstance(obj, clas) or issubclass(obj.__class__, clas):
return 1
else:
return 0
def wx_generic_binder(widget, function):
'''
TextCtrl(wx.EVT_TEXT) and Slider(wx.EVT_SLIDER) are supported for now.
'''
if widget is not None:
if checkclass(widget, wx.TextCtrl):
widget.Bind(wx.EVT_TEXT, function)
elif checkclass(widget, wx.Slider):
widget.Bind(wx.EVT_SLIDER, function)
else:
raise NotImplementedError
class TopicsNotebook(wx.Notebook):
def __init__(self, parent, forced_frame_handler):
wx.Notebook.__init__(self, parent)
self.pages = []
for count in range(3):
self.pages.append(VideoPanel(self,forced_frame_handler))
self.AddPage(self.pages[-1], str(count))
class VideoPanel(wx.Panel):
'''
A video panel implementation
'''
def __init__(self, parent, forced_frame_handler):
'''
data is a list of frames. If a frame is missing,
the entry is None
'''
wx.Panel.__init__(self, parent, wx.NewId())
self.forced_frame_handler = forced_frame_handler
wx_generic_binder(self.forced_frame_handler,
lambda event: self.handle_forced(event, self)
)
self.forced = 0
print 'from __init__', id(self)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.Bind(wx.EVT_PAINT, self.on_playing)
wx.CallLater(200, self.SetFocus)
self.img = None
def handle_forced(self, event, parent):
self.count = self.forced_frame_handler.GetValue()
self.forced = 1
print 'from handle_forced', id(self)
self.on_playing(None)
def on_playing(self, event):
print 'from on_playing', id(self)
class MainFrame(wx.Frame):
'''
Main Processing Window
'''
def __init__(self, parent, id_, title):
wx.Frame.__init__(self, parent, id_, title)
self.main_panel = wx.Panel(self, wx.NewId())
self.lft_box = wx.BoxSizer(wx.VERTICAL)
self.slider_min = wx.Slider(self.main_panel, -1, 0, 0,
99, size=(600, -1),
style=wx.SL_VALUE_LABEL)
self.lft_box.Add(self.slider_min)
self.rgt_box = wx.BoxSizer(wx.VERTICAL)
self.nb = TopicsNotebook(self, forced_frame_handler=self.slider_min)
self.rgt_box.Add(self.nb, 1, wx.EXPAND | wx.ALL)
self.main_panel.Fit()
self.main_box = wx.BoxSizer(wx.HORIZONTAL)
self.main_box.AddMany([(self.lft_box, 1),
(self.rgt_box, 1)])
self.SetSizerAndFit(self.main_box)
wx.CallLater(200, self.SetFocus)
def main():
'''
main function
'''
app = wx.App(0)
frame = MainFrame(None , -1, 'Data Mining')
frame.Show(True)
app.MainLoop()
main()
结果为:(如果有人移动滑块)
from __init__ 139699098836624
from __init__ 139699098836016
from __init__ 139699098624232
from on_playing 139699098836624
from on_playing 139699098836624
from on_playing 139699098836624
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
可以看到on_playing在所有调用的时候都有相同的id(??),不服从init id。 handle_forced 调用了 one_playing 的前三个调用之后的事件,这就是我得到相同 ID 的原因。从 3 个不同的 handle_forced 实例中得到 3 个这样的事件是正常的,但我只得到最后一个。总而言之,ID 被搞乱了,每个处理程序只设置了一个(随机?)绑定。欢迎有足够耐心的人给我解释一下。谢谢!
您基本上将同一事件类型绑定到同一小部件 3 次。当事件发生时,系统会查找绑定,调用它找到的第一个绑定,然后假定它已完成并且 returns。如果您希望系统继续寻找匹配的绑定,那么您需要在处理函数中调用 event.Skip()
。
我正在尝试创建一个 wxPython 应用程序。简化我的设置,假设我有一个左面板和一个右面板。左侧面板有我的控件,它们是 sliders/buttons/etc。右侧面板包括一个笔记本,在每个选项卡中我都显示从图像数据列表中获取的视频帧。如果我不使用笔记本,一切都很好,控制事件改变了右侧面板的功能。但是,当我实现笔记本时,考虑了笔记本内每个面板和每个控件的多重绑定,我得到了一些奇怪的行为。发生的情况是每个控件似乎都有不同的父控件,因此我无法将同一 class(!!!) 内的变量从一种方法传递到另一种方法。由于问题的复杂性,我无法解释结果。下面是一个例子:
import wx
import numpy as np
def checkclass(obj, clas):
if isinstance(obj, clas) or issubclass(obj.__class__, clas):
return 1
else:
return 0
def wx_generic_binder(widget, function):
'''
TextCtrl(wx.EVT_TEXT) and Slider(wx.EVT_SLIDER) are supported for now.
'''
if widget is not None:
if checkclass(widget, wx.TextCtrl):
widget.Bind(wx.EVT_TEXT, function)
elif checkclass(widget, wx.Slider):
widget.Bind(wx.EVT_SLIDER, function)
else:
raise NotImplementedError
class TopicsNotebook(wx.Notebook):
def __init__(self, parent, forced_frame_handler):
wx.Notebook.__init__(self, parent)
self.pages = []
for count in range(3):
self.pages.append(VideoPanel(self,forced_frame_handler))
self.AddPage(self.pages[-1], str(count))
class VideoPanel(wx.Panel):
'''
A video panel implementation
'''
def __init__(self, parent, forced_frame_handler):
'''
data is a list of frames. If a frame is missing,
the entry is None
'''
wx.Panel.__init__(self, parent, wx.NewId())
self.forced_frame_handler = forced_frame_handler
wx_generic_binder(self.forced_frame_handler,
lambda event: self.handle_forced(event, self)
)
self.forced = 0
print 'from __init__', id(self)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.Bind(wx.EVT_PAINT, self.on_playing)
wx.CallLater(200, self.SetFocus)
self.img = None
def handle_forced(self, event, parent):
self.count = self.forced_frame_handler.GetValue()
self.forced = 1
print 'from handle_forced', id(self)
self.on_playing(None)
def on_playing(self, event):
print 'from on_playing', id(self)
class MainFrame(wx.Frame):
'''
Main Processing Window
'''
def __init__(self, parent, id_, title):
wx.Frame.__init__(self, parent, id_, title)
self.main_panel = wx.Panel(self, wx.NewId())
self.lft_box = wx.BoxSizer(wx.VERTICAL)
self.slider_min = wx.Slider(self.main_panel, -1, 0, 0,
99, size=(600, -1),
style=wx.SL_VALUE_LABEL)
self.lft_box.Add(self.slider_min)
self.rgt_box = wx.BoxSizer(wx.VERTICAL)
self.nb = TopicsNotebook(self, forced_frame_handler=self.slider_min)
self.rgt_box.Add(self.nb, 1, wx.EXPAND | wx.ALL)
self.main_panel.Fit()
self.main_box = wx.BoxSizer(wx.HORIZONTAL)
self.main_box.AddMany([(self.lft_box, 1),
(self.rgt_box, 1)])
self.SetSizerAndFit(self.main_box)
wx.CallLater(200, self.SetFocus)
def main():
'''
main function
'''
app = wx.App(0)
frame = MainFrame(None , -1, 'Data Mining')
frame.Show(True)
app.MainLoop()
main()
结果为:(如果有人移动滑块)
from __init__ 139699098836624
from __init__ 139699098836016
from __init__ 139699098624232
from on_playing 139699098836624
from on_playing 139699098836624
from on_playing 139699098836624
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
from handle_forced 139699098624232
from on_playing 139699098624232
可以看到on_playing在所有调用的时候都有相同的id(??),不服从init id。 handle_forced 调用了 one_playing 的前三个调用之后的事件,这就是我得到相同 ID 的原因。从 3 个不同的 handle_forced 实例中得到 3 个这样的事件是正常的,但我只得到最后一个。总而言之,ID 被搞乱了,每个处理程序只设置了一个(随机?)绑定。欢迎有足够耐心的人给我解释一下。谢谢!
您基本上将同一事件类型绑定到同一小部件 3 次。当事件发生时,系统会查找绑定,调用它找到的第一个绑定,然后假定它已完成并且 returns。如果您希望系统继续寻找匹配的绑定,那么您需要在处理函数中调用 event.Skip()
。