【问题标题】:Programmatic binding of accelerators in wxPythonwxPython中加速器的编程绑定
【发布时间】:2012-10-17 22:26:15
【问题描述】:

我正在尝试以编程方式在 wxPython 中循环创建和绑定一个加速器表,这样我就不必担心为每个加速器获取和分配新 ID(并希望从一些外部资源,而不是硬编码它们)。我还通过 lambda 将一些参数传递给处理程序,因为我的许多处理程序都是相同的,但具有不同的参数(移动、缩放等)。

该类是 wx.Frame 的子类,并在初始化期间调用 setup_accelerators()

def setup_accelerators(self):

    bindings = [
                  (wx.ACCEL_CTRL,  wx.WXK_UP, self.on_move, 'up'),
                  (wx.ACCEL_CTRL,  wx.WXK_DOWN, self.on_move, 'down'),
                  (wx.ACCEL_CTRL,  wx.WXK_LEFT, self.on_move, 'left'),
                  (wx.ACCEL_CTRL,  wx.WXK_RIGHT, self.on_move, 'right'),
                  ]


    accelEntries = []

    for binding in bindings:
        eventId = wx.NewId()
        accelEntries.append( (binding[0], binding[1], eventId) )

        self.Bind(wx.EVT_MENU, lambda event: binding[2](event, binding[3]), id=eventId)


    accelTable = wx.AcceleratorTable(accelEntries)
    self.SetAcceleratorTable(accelTable)

def on_move(self, e, direction):
    print direction

但是,这似乎将所有加速键绑定到最后一个条目,因此 Ctrl+Up 打印"right",其他三个也是如此。这种方式如何正确绑定多个handler?

【问题讨论】:

    标签: python event-handling wxpython


    【解决方案1】:

    知道了。问题是您没有将您的方向作为参数传递给您的 lambda(它只查看事件参数(和 self),因为这就是您的 lambda 被定义为接受)This 页面给了我帮助需要让这个工作(这里是gist):

    import wx
    
    class MyForm(wx.Frame):
    
        #----------------------------------------------------------------------
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "Programmatic binding of accelerators in wxPython", size=(450,150))
    
            # Add a panel so it looks the correct on all platforms
            panel = wx.Panel(self, wx.ID_ANY)
            bindings = [
                      (wx.ACCEL_CTRL,  wx.WXK_UP, 'up'),
                      (wx.ACCEL_CTRL,  wx.WXK_DOWN, 'down'),
                      (wx.ACCEL_CTRL,  wx.WXK_LEFT, 'left'),
                      (wx.ACCEL_CTRL,  wx.WXK_RIGHT, 'right'),
                      ]
    
    
            accelEntries = []
    
            for binding in bindings:
                eventId = wx.NewId()
                accelEntries.append( (binding[0], binding[1], eventId) )
    
                self.Bind(wx.EVT_MENU, lambda evt, temp=binding[2]: self.on_move(evt, temp), id=eventId)
    
            accelTable  = wx.AcceleratorTable(accelEntries)
            self.SetAcceleratorTable(accelTable )
         #----------------------------------------------------------------------
    
        def on_move(self, Event, direction):
            print "You pressed CTRL+"+direction
    
    # Run the program
    if __name__ == "__main__":
        app = wx.App(False)
        frame = MyForm()
        frame.Show()
        app.MainLoop()
    

    我的原始答案(这是一个可接受的替代解决方案)是:

    import wx
    
    class MyForm(wx.Frame):
    
        #----------------------------------------------------------------------
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial", size=(500,500))
    
            # Add a panel so it looks the correct on all platforms
            panel = wx.Panel(self, wx.ID_ANY)
            bindings = [
                      (wx.ACCEL_CTRL,  wx.WXK_UP, self.on_move_up),
                      (wx.ACCEL_CTRL,  wx.WXK_DOWN, self.on_move_down),
                      (wx.ACCEL_CTRL,  wx.WXK_LEFT, self.on_move_left),
                      (wx.ACCEL_CTRL,  wx.WXK_RIGHT, self.on_move_right),
                      ]
    
    
            accelEntries = []
    
            for binding in bindings:
                eventId = wx.NewId()
                accelEntries.append( (binding[0], binding[1], eventId) )
    
                self.Bind(wx.EVT_MENU, binding[2], id=eventId)
    
            accelTable  = wx.AcceleratorTable(accelEntries)
            self.SetAcceleratorTable(accelTable )
         #----------------------------------------------------------------------
        def on_move_up(self, event):
            print "You pressed CTRL+up"
        def on_move_down(self, event):
            print "You pressed CTRL+down"
        def on_move_left(self, event):
            print "You pressed CTRL+left"
        def on_move_right(self, event):
            print "You pressed CTRL+right"
    
    # Run the program
    if __name__ == "__main__":
        app = wx.App(False)
        frame = MyForm()
        frame.Show()
        app.MainLoop()
    

    【讨论】:

    • 谢谢,如果我不能让 lambda 工作,我会这样做(尽管这意味着我必须在我的代码中添加更多的处理程序)。但是,我仍然不明白为什么在一个额外的参数中进行 lambda'ing(实际上从未查看过该事件)在这里不起作用。
    • 我找到了一个与您尝试解决此问题的方式相同的解决方案。但是,我保留了原始解决方案,因为即使您想避免定义太多功能,这些按钮都会做不同的事情,因此不同的功能会更加清晰。
    • 太棒了!我添加了一点,这意味着我也可以选择回调(我有 4 个“移动”函数、4 个“拉伸”函数、4 个“缩放”函数、4 个“平移”函数,还有很多其他类似的函数,所以它节省了如果我可以传递参数,则重复很多)。我通过添加到 lambda 来做到这一点:self.Bind(wx.EVT_MENU, lambda event, arg=binding[3], func=binding[2]: func(event, arg), id=eventId)
    猜你喜欢
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 2021-02-13
    • 2010-09-09
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多