创建多个 wx.AcceleratorEntry() 条目并将函数绑定到它们的正确方法是什么? wxPython

What is the right way to create multiple wx.AcceleratorEntry() entries and bind functions to them? wxPython

目前我正在做我的 wxPython 高中期末项目,我正面临另一个问题 我想将按键组合条目(例如CTRL+S...)绑定到我的功能,但我无法达到我期望的结果。

这个我试过了,但是按键没有绑定。

accelnum = 2

        accelerators = [wx.AcceleratorEntry() for x in range(accelnum)]

        accelerators[0].Set(wx.ACCEL_CTRL, ord('S'), 'save')
        accelerators[1].Set(wx.ACCEL_CTRL, ord('E'), 'export')


        accel=wx.AcceleratorTable(accelerators)
        self.SetAcceleratorTable(accel)


def save(self, event):
        # some code...

def export(self, event):
        # some other code...

我也尝试将 ID 设置为与我设置工具栏工具相同的 ID,但它说 'id' 在这里不是有效参数。

非常感谢您的所有建议。 R

编辑

对于所有想知道可能有什么问题的人,我还使用 wx.EVT_CHAR_HOOK 来检测 "DEL" 键。当我第二次重写我的 class 时,我忘记添加 EVT_CHAR_HOOK 并且它起作用了。直到我添加 EVT_CHAR_HOOK 回来。这意味着您不能同时使用它。所以我接下来做了什么:

ID_SAVE = wx.NewIdRef()
ID_EXPORT = wx.NewIdRef()
ID_DELETE = wx.NewIdRef()
accelerators = [wx.AcceleratorEntry() for x in range(3)]
accelerators[0].Set(wx.ACCEL_CTRL, ord('S'), ID_SAVE)
accelerators[1].Set(wx.ACCEL_CTRL, ord('E'), ID_EXPORT)
accelerators[2].Set(wx.ACCEL_NORMAL, wx.WXK_DELETE, ID_DELETE)

同时分配我的删除按钮,现在可以使用了

参见:https://docs.wxpython.org/wx.AcceleratorEntry.html#wx.AcceleratorEntry.Set

Set 的第三个参数应该是创建和发送事件时要使用的 ID。所以你会想这样做:

    ID_SAVE = wx.NewIdRef()
    accelerators[0].Set(wx.ACCEL_CTRL, ord('S'), ID_SAVE)

当按下该键时,将发送一个 EVT_MENU 事件,因此您还需要为其绑定一个处理程序,如下所示:

    self.Bind(wx.EVT_MENU, self.save, id=ID_SAVE)

Robin 的回答一如既往地有效。
您可能希望检查一下您是如何实施它的。
尝试这样的事情:

import wx

ID_SAVE = wx.NewIdRef()
ID_EXPORT = wx.NewIdRef()
accelerators = [wx.AcceleratorEntry() for x in range(2)]
accelerators[0].Set(wx.ACCEL_CTRL, ord('S'), ID_SAVE)
accelerators[1].Set(wx.ACCEL_CTRL, ord('E'), ID_EXPORT)

class MyFrame(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="", size=(360,100)):
        super(MyFrame, self).__init__(parent, id, title, size)
        accel=wx.AcceleratorTable(accelerators)
        self.SetAcceleratorTable(accel)
        self.panel = wx.Panel(self)
        self.Bind(wx.EVT_MENU, self.OnSave, id=ID_SAVE)
        self.Bind(wx.EVT_MENU, self.OnExport, id=ID_EXPORT)
        self.Show()

    def OnSave(self, event):
        print("Save")
        event.Skip()

    def OnExport(self, event):
        print("Export")
        event.Skip()

if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame(None,title="An Accelerator Test")
    app.MainLoop()

其他答案已经解释了'how to'。也许这个例子可以让新读者更容易编码。

正如您在其他答案中所读到的,创建加速器需要 3 个步骤:1) 创建一个 id,2) 创建一个加速器,以及 3) 绑定到 EVT_MENU。我自己花了一些时间让它工作。

所以在 'getting the right way' 之后,我创建了一种让我更容易的方法,“更简单的方法”,当使用很多加速器时,通过将它们定义在一个中地方。

        self._accelerators = {

            wx.NewIdRef(): {'text': 'Previous Page (PageUp)',
                            'flags': wx.ACCEL_NORMAL,
                            'keyCode': wx.WXK_PAGEUP,
                            'handler': self.on_previous},

            wx.NewIdRef(): {'text': 'Next Page (PageDown)',
                            'flags': wx.ACCEL_NORMAL,
                            'keyCode': wx.WXK_PAGEDOWN,
                            'handler': self.on_next},

            wx.NewIdRef(): {'text': 'Select All (Ctrl+A)',
                            'flags': wx.ACCEL_CTRL,
                            'keyCode': ord('a'),
                            'handler': self.on_select_all},
        }

然后让python做无聊的事情。

# ------------------------------------------------------------------------------------------------------------------
def _create_accelerators(self):

    entries = []
    for event_id, accelerator in self._accelerators.items():

        # create the accelerator ---------------------------------------------
        entry = wx.AcceleratorEntry(accelerator['flags'], accelerator['keyCode'], event_id)
        entries.append(entry)

        # bind handler to EVT_MENU ----------------------------------------
        self.Bind(wx.EVT_MENU, accelerator['handler'], id=event_id)

    accel_tbl = wx.AcceleratorTable(entries)
    self.SetAcceleratorTable(accel_tbl)

一个完整的工作示例。

import wx


class MyForm(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="Accelerator Test", size=(500, 500))

        panel = wx.Panel(self, wx.ID_ANY)

        # define the accelerators ---------------------------------------------
        self._accelerators = {

            wx.NewIdRef(): {'text': 'Previous Page (PageUp)',
                            'flags': wx.ACCEL_NORMAL,
                            'keyCode': wx.WXK_PAGEUP,
                            'handler': self.on_previous},

            wx.NewIdRef(): {'text': 'Next Page (PageDown)',
                            'flags': wx.ACCEL_NORMAL,
                            'keyCode': wx.WXK_PAGEDOWN,
                            'handler': self.on_next},

            wx.NewIdRef(): {'text': 'Select All (Ctrl+A)',
                            'flags': wx.ACCEL_CTRL,
                            'keyCode': ord('a'),
                            'handler': self.on_select_all},

        }

        # create the accelerators ---------------------------
        self._create_accelerators()

    # ----------------------------------------------------------------------
    def _create_accelerators(self):

        entries = []
        for event_id, accelerator in self._accelerators.items():

            # create the accelerator ---------------------------------------------
            entry = wx.AcceleratorEntry(accelerator['flags'], accelerator['keyCode'], event_id)
            entries.append(entry)

            # bind handler to EVT_MENU ----------------------------------------
            self.Bind(wx.EVT_MENU, accelerator['handler'], id=event_id)

        accel_tbl = wx.AcceleratorTable(entries)
        self.SetAcceleratorTable(accel_tbl)

    # -------------------------------------------------------------------------------
    def on_previous(self, event):

        print(f"You pressed {self._accelerators[event.GetId()]['text']}")

    # -------------------------------------------------------------------------------
    def on_next(self, event):

        print(f"You pressed {self._accelerators[event.GetId()]['text']}")

    # -------------------------------------------------------------------------------
    def on_select_all(self, event):

        print(f"You pressed {self._accelerators[event.GetId()]['text']}")


# ===================================================================================
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()

一些输出。

You pressed Next Page (PageDown)
You pressed Previous Page (PageUp)
You pressed Select All (Ctrl+A)