Python 2.7 wxPython 4:检测双击键

Python 2.7 wxPython 4:检测双击键,python-2.7,events,keyboard-shortcuts,wxpython,Python 2.7,Events,Keyboard Shortcuts,Wxpython,wxPython 4是否有办法识别双重按下相同的键? 特别是在我的情况下,我想知道何时快速连续按下SHIFT键两次。我认为问题在于,当几个键同时触发时,他不想得到通知,而是一个接一个地被触发。我并没有找到一个本地的方法来做这件事,所以我自己尝试了。我的解决方案在TestFrame中导致了丑陋的状态,因此如果wxPython中存在本机方法,我也会感兴趣 import wx import time class TestFrame(wx.Frame): def __init__(self,

wxPython 4是否有办法识别双重按下相同的键?
特别是在我的情况下,我想知道何时快速连续按下SHIFT键两次。

我认为问题在于,当几个键同时触发时,他不想得到通知,而是一个接一个地被触发。我并没有找到一个本地的方法来做这件事,所以我自己尝试了。我的解决方案在TestFrame中导致了丑陋的状态,因此如果wxPython中存在本机方法,我也会感兴趣

import wx
import time

class TestFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        self._keyCounter = 0
        self._lastKeyTs = -1

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.Bind(wx.EVT_KEY_DOWN, self._OnKeyDown)
        self.SetSizer(sizer)

    def _OnKeyDown(self, event):
        self._keyCounter += 1
        if self._keyCounter % 2 == 0 and time.time() - self._lastKeyTs < 0.3:
            print "Trigger"
        self._lastKeyTs = time.time()

class App(wx.App):
    def OnInit(self):
        frmMain = TestFrame(None)
        frmMain.SetSize(wx.Size(800, 600))

        frmMain.Show()

        return True


if __name__ == '__main__':
    application = App(False)
    application.MainLoop()
导入wx
导入时间
类TestFrame(wx.Frame):
定义初始化(自身,父级):
wx.Frame.\uuuu init\uuuuux(自,父)
self.\u keyCounter=0
self.\u lastKeyTs=-1
sizer=wx.BoxSizer(wx.VERTICAL)
self.Bind(wx.EVT\u KEY\u DOWN,self.\u onkey DOWN)
自整定器(施胶器)
def_OnKeyDown(自身、事件):
自。_键计数器+=1
如果self.\u keyCounter%2==0和time.time()-self.\u lastKeyTs<0.3:
打印“触发器”
self.\u lastKeyTs=time.time()
类应用程序(wx.App):
def OnInit(自身):
frmMain=TestFrame(无)
最小设置尺寸(宽x.尺寸(800600))
frmMain.Show()
返回真值
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
应用程序=应用程序(错误)
application.MainLoop()

这一点并不像看上去那么明显

下面的代码使用“一次性”计时器在250毫秒后重新设置上一个键,以解决“快速连续”问题。当然,您可以将其设置为任何适当的值。 对于wxPython的旧版本,计时器没有
StartOnce
选项,您必须使用
Start(250,oneShot=True)

我允许使用除
Shift
之外的其他键,这使它稍微复杂了一点,而名称字典只是为了测试目的

我应该指出,因为这必须检查每一次关键的萧条,这不是很有效,但我想你知道这一点,并愿意为此付出代价

我有一个警告,我不知道在非Linux机器上按住shift键会有什么反应。如果证明它与Linux不同,那么您应该将
Bind
wx.EVT\u KEY\u DOWN
更改为
wx.EVT\u KEY\u UP

import wx
import time
class Frame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__ (self, parent, -1, title = "Test Frame", size = (500,360))

        self.text_window = wx.TextCtrl(self, wx.ID_ANY, "", size = (450,250), style = wx.TE_MULTILINE)
        self.text_window.Bind(wx.EVT_KEY_DOWN, self.key_info)

        #Define a timer to reset the key values
        self.key_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.Ontimer, self.key_timer)

        #Define storage for the previous key
        self.prev_key = 0

        #Define the set of double keys we are looking for and a dict  of their names
        # Shift is 306 (on my keyboard), Alt is 307 and Ctrl is 308
        self.double_keys = (306,307,308)
        self.names = {'306':'Shift','307':'Alt','308':'Ctrl'}

        sizer1= wx.BoxSizer(wx.VERTICAL)
        sizer1.Add(self.text_window, 0, wx.ALL, 5)
        self.SetSizer(sizer1)
        self.Show()

    def key_info(self, event):
        self.key = event.GetKeyCode()
        if self.key in self.double_keys and self.prev_key == self.key:
            self.text_window.AppendText("Double key "+self.names[str(self.key)]+" used within a quarter second\n")
        self.prev_key = self.key
        #fire up the timer to execute once to reset the previous key
        if self.key in self.double_keys:
            self.key_timer.StartOnce(250)
        # Skip so this doesn't consume the key event itself
        event.Skip()

    def Ontimer(self,event):
        # Re-set the previous key after 250 milliseconds
        self.prev_key = 0

app = wx.App()
frame = Frame(None)
app.MainLoop()
注意:我从您在评论中的对话中注意到,这不仅是您关于堆栈溢出的第一个问题,而且您似乎对这些评论有点反感

如果你不提供你的代码,不管你是工作还是失败得很惨,你都会吸引选票。论坛成员希望看到代码,特别是您已经尝试过的代码。基本上,这只是一个基本的指标,表明你自己是否已经在回答这个问题上付出了努力,然后再提出一个一行字的问题,希望其他人能帮你做腿部工作

我最近发布了一个自我回答的问题,其中的问题和答案发布在一起。尽管我对自己的问题给出了详细的编码答案,但我还是立即收到了反对票。所以不要把它当成个人的事。我怀疑有些人仅仅是通过“非常”严格地遵守“规则”就能获得乐趣。

也就是说,如果你坚持一段时间,自己回答问题,你就会开始在问题和MCVE中看到代码的优点。你会惊讶于一些人所发布的内容,期望得到答案。

这里有一个更通用的解决方案

使用事件
EVT\u CHAR\u HOOK
代替
EVT\u KEY\u UP
EVT_KEY_UP
的问题是,当事件绑定到包含面板的帧时,它会被吞没

EVT\u CHAR\u HOOK
的挑战是确定该键是实际按下两次还是仅按住一次。因此,将读取RawKeyFlags。位置30处的位指示是否持有钥匙

但是,请注意,此解决方案仅适用于Windows系统

import wx

class DoubleKeyStrokeListener(object):
    def __init__(self, parent, keyCode, callback, timeout=500):
        self._monitoredKey = keyCode
        self._callback = callback
        self._timeout = timeout

        self._firstPressRecognized = False
        self._keyTimer = wx.Timer(parent)

        parent.Bind(wx.EVT_CHAR_HOOK, self._OnKeyPressed)
        parent.Bind(wx.EVT_TIMER, self._OnTimer, self._keyTimer)

    def _OnKeyPressed(self, event):
        event.Skip()

        pressedKey = event.GetKeyCode()

        if pressedKey == self._monitoredKey:
            rawFlags = event.GetRawKeyFlags()

            # bit at position 30 is "previous key state" flag
            prevStateBit = rawFlags >> 30 & 1

            if prevStateBit == 1:  # -> key is held
                return

            if self._firstPressRecognized:
                self._firstPressRecognized = False
                self._callback(event)
            else:
                self._firstPressRecognized = True
                self._keyTimer.StartOnce(self._timeout)
        else:
            self._firstPressRecognized = False

    def _OnTimer(self, event):
        self._firstPressRecognized = False
        event.Skip()

我已经看过《如何提问》了,所以我不理解否决票。你认为我的问题中缺少信息吗?检查这个和这个我已经找到了这些问题,这些问题的答案对我没有帮助,原因有二。1.我必须和wxPython一起工作,2。我必须识别同一行中是否按了两次相同的(!)键,因此感谢您的回答!这并不完全是我所希望的,但基于您的示例,我现在创建了一个类,可以更一般地解决这个问题,这对我来说已经足够了:-)@J.Doe如果您觉得我的答案不值得接受或投票表决,您可以随时发布自己的代码作为答案。这样,任何其他有类似问题的人都可以找到一个例子。毕竟,这就是所谓的一切。