wxPython:在OSX上获取CMD + [其他密钥]的EVT_KEY_DOWN事件

时间:2014-02-19 12:16:29

标签: macos wxpython

当用户在OSX上按下COMMAND + [任何其他键]时,我正试图捕获一个事件。由于这些实际上是两次按键,我期待两个事件:一个是按下COMMAND,一个是按下另一个按键(不释放COMMAND键)。这适用于除COMMAND之外的每个修饰符,其中我只获得第一个事件。为什么这样,我该如何解决?

版本:wxPython3.0-osx-cocoa-py2.7

示例代码:

import wx

def OnKeyDown(e):
    print "Modifiers: {} Key Code: {}".format(e.GetModifiers(), e.GetKeyCode())

app = wx.App()
frame = wx.Frame(None)

textctrl = wx.TextCtrl(frame, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.WANTS_CHARS)
textctrl.Bind(wx.EVT_KEY_DOWN, OnKeyDown)

frame.Show()
app.MainLoop()

对于ALT + d,输出为:

Modifiers: 1 Key Code: 307
Modifiers: 1 Key Code: 68

对于SHIFT + d,输出为:

Modifiers: 4 Key Code: 306
Modifiers: 4 Key Code: 68

仅对于COMMAND + d,输出为:

Modifiers: 2 Key Code: 308

感谢您的帮助

其他信息:我在虚拟机上使用OSX 10.8 。正如RobinDunn指出它可以在他的笔记本电脑上运行。所以很有可能这只是我环境中的一个问题。 wnnmaw提供了一个很好的解决方法,即使在虚拟环境中也适用于我。

1 个答案:

答案 0 :(得分:0)

好吧,所以我花了一些时间,但这是一个可以完成你想要的工作代码块。

有些注意事项:

  • 我在Windows上执行了此操作(因此您可以进行一些更改,例如添加wx.ACCEL_RAW_CTRL的支持,该支持对应于Mac上的实际控制键,而wx.ACCCEL_CTRL对应于命令键
  • 此代码绝对可以(并且需要)清理
  • 在向用户提供之前,您必须添加更好的错误检查

没有进一步的说法,这里是

import wx
from wx.lib.scrolledpanel import ScrolledPanel

class TestWindow(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Accelerator Table Test', size=(600, 400))

        self.panel = ScrolledPanel(parent=self, id=-1) 
        self.panel.SetupScrolling()

        #Create IDs to be used in initial acclerator table
        self.functionList = [self.func1, self.func2, self.func3, self.func4, self.func5, self.OnAdd, self.OnDel]
        self.functionListstr = ["self.func1", "self.func2", "self.func3", "self.func4", "self.func5", "self.OnAdd", "self.OnDel"]
        self.IDDict = {i: wx.NewId() for i in range(len(self.functionList))}
        self.IDDictrev = {val:key for key, val in self.IDDict.iteritems()}

        self.aTableList = [(wx.ACCEL_ALT, ord('S'), self.IDDict[0]),(wx.ACCEL_CTRL, ord('Q'), self.IDDict[1])]

        #Set up initial accelerator table
        aTable = wx.AcceleratorTable(self.aTableList)
        self.SetAcceleratorTable(aTable)

        #Bind inital accelerator table IDs to functions
        for i in range(len(self.functionList)):
            self.Bind(wx.EVT_MENU, self.functionList[i], id=self.IDDict[i]) 


        #Set up control widgets on GUI    
        self.flexgrid = wx.FlexGridSizer(cols=3, hgap=10, vgap=5)

        cmdkeylbl = wx.StaticText(self.panel, -1, "Command Key") 
        self.cmdkey = wx.ComboBox(self.panel, style=wx.CB_READONLY)
        cmdkeylist = ["Alt", "Control/Command", "Shift", "OSX Control", "None"]
        self.cmdkeyconstants = {"Alt":wx.ACCEL_ALT, "Control/Command":wx.ACCEL_CTRL, "Shift":wx.ACCEL_SHIFT, "None":wx.ACCEL_NORMAL}
        self.cmdkeyconstantsrev = {val:key for key, val in self.cmdkeyconstants.iteritems()}
        self.cmdkey.SetItems(cmdkeylist)

        hotkeylbl = wx.StaticText(self.panel, -1, "HotKey (single letter only)") 
        self.hotkey = wx.TextCtrl(self.panel, size=(50,-1))

        funclbl = wx.StaticText(self.panel, -1, "Function") 
        self.func = wx.ComboBox(self.panel, style=wx.CB_READONLY)
        self.func.SetItems(self.functionListstr)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)

        addBtn = wx.Button(self.panel, -1, "Add")
        delBtn = wx.Button(self.panel, -1, "Delete")

        self.Bind(wx.EVT_BUTTON, self.OnAdd, addBtn)
        self.Bind(wx.EVT_BUTTON, self.OnDel, delBtn)

        self.vbox = wx.BoxSizer(wx.VERTICAL)

        self.curATable = wx.StaticText(self.panel, -1, self._DisplayATable())

        self.flexgrid.Add(cmdkeylbl)
        self.flexgrid.Add(hotkeylbl)
        self.flexgrid.Add(funclbl)
        self.flexgrid.Add(self.cmdkey)
        self.flexgrid.Add(self.hotkey)
        self.flexgrid.Add(self.func)

        self.hbox.Add((20, 20), 0)
        self.hbox.Add(addBtn)
        self.hbox.Add((0, 0), 0)
        self.hbox.Add(delBtn)
        self.hbox.Add((20, 20), 0)

        self.vbox.Add(self.flexgrid, flag=wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        self.vbox.Add(self.hbox, flag=wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        self.vbox.Add(self.curATable, flag=wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)

        self.panel.SetSizer(self.vbox)
        self.panel.Layout()

    #Class Functions
    def _DisplayATable(self):
        aTablelbl = ""
        for cmdKey, hotKey, Func in self.aTableList:
            aTablelbl += "{} + {} calls {}\n".format(self.cmdkeyconstantsrev[cmdKey], chr(hotKey), self.functionListstr[self.IDDictrev[Func]])

        return aTablelbl

    def OnAdd(self, event):
        self.aTableList.append((self.cmdkeyconstants[self.cmdkey.GetValue()], ord(self.hotkey.GetValue()[:1].title()), self.IDDict[self.func.GetSelection()]))
        print "Added {} + {} as a shortcut for {}!".format(self.cmdkey.GetValue(), self.hotkey.GetValue()[:1].title(), self.functionListstr[self.func.GetSelection()])

        aTable = wx.AcceleratorTable(self.aTableList)
        self.SetAcceleratorTable(aTable)
        self.curATable.SetLabel(self._DisplayATable())
        self.panel.Layout()

    def OnDel(self, event):
        if (self.cmdkeyconstants[self.cmdkey.GetValue()], ord(self.hotkey.GetValue()[:1].title()), self.IDDict[self.func.GetSelection()]) in self.aTableList:
            self.aTableList.remove((self.cmdkeyconstants[self.cmdkey.GetValue()], ord(self.hotkey.GetValue()[:1].title()), self.IDDict[self.func.GetSelection()]))

            aTable = wx.AcceleratorTable(self.aTableList)
            self.SetAcceleratorTable(aTable)
            self.curATable.SetLabel(self._DisplayATable())
            self.panel.Layout()

        else:
            dlg = wx.MessageDialog(self, "ERROR: That combination is not in the accelerator table!", "Error", style=wx.OK)
            dlg.ShowModal()
            dlg.Destroy()

    def func1(self, event):
        dlg = wx.MessageDialog(self, "Func1", "Func1", style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def func2(self, event):
        dlg = wx.MessageDialog(self, "Func2", "Func2", style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def func3(self, event):
        dlg = wx.MessageDialog(self, "Func3", "Func3", style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def func4(self, event):
        dlg = wx.MessageDialog(self, "Func4", "Func4", style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def func5(self, event):
        dlg = wx.MessageDialog(self, "Func5", "Func5", style=wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

app = wx.App(False)
frame = TestWindow()
frame.Show()
app.MainLoop()

希望这是您正在寻找的,如果您有任何问题,请告诉我