在wxPython 4中,有没有一种方法可以识别两次按下相同的键?特别是在我的例子中,我想要识别当快速连续按下SHIFT键两次时的情况。
发布于 2018-08-08 03:40:48
下面是一个更通用的解决方案
使用事件EVT_CHAR_HOOK
而不是EVT_KEY_UP
。EVT_KEY_UP
的问题在于,当事件绑定到包含面板的框架时,它会被吞并。
EVT_CHAR_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()
发布于 2018-08-07 01:31:21
这一点并不像乍看起来那么明显。
下面的代码,使用“一次”wx.Timer
在250毫秒后重新设置前一个密钥,以解决“快速连续”的问题。当然,您可以将其设置为任何合适的值。对于较早版本的wxPython,计时器没有StartOnce
选项,您必须使用Start(250, oneShot=True)
我把它稍微复杂化了,允许使用Shift
以外的键,而名称字典只是为了测试。
我应该指出的是,因为它必须检查每个键按键,所以效率不是很高,但我想你已经意识到了这一点,并愿意为此付出代价。
我确实有一个警告,我不知道在非Linux机器上按住一个键,比如Shift键,会有什么反应。如果事实证明它不像Linux,那么您应该将Bind
从wx.EVT_KEY_DOWN
改为wx.EVT_KEY_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()
注意:我从你们在评论中的对话中注意到,这不仅是你们在Stack Overflow上的第一个问题,而且你们似乎对评论有点不满。
如果你不提供你的代码,工作或失败的痛苦,你将吸引下投票。论坛的成员喜欢看到代码,特别是你已经尝试过的代码。它基本上只是一个基本的指标,表明你是否花了任何努力回答自己的问题,然后抛出一个一行的问题,并希望其他人为你做腿上的工作。
我最近发布了一个自我回答的问题,问题和答案放在一起。尽管我对我自己的问题提供了详细的编码答案,但我立即对这个问题投了反对票。所以不要把它放在心上。我怀疑有些人只是通过严格遵守“规则”来获得乐趣。
也就是说,如果你坚持一段时间,自己回答问题,你就会开始看到问题和MCVE中代码的优点。你会惊讶于有些人发布了什么,期待着一个答案。
发布于 2018-08-06 20:28:26
我认为问题是,当几个键同时被触发时,他不想得到通知,而是一个接一个地短。我没有找到一种原生的方法,所以我自己尝试了一下。我的解决方案在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()
https://stackoverflow.com/questions/51703466
复制相似问题