Python 2.7 wxPython 4:检测双击键
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,
特别是在我的情况下,我想知道何时快速连续按下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如果您觉得我的答案不值得接受或投票表决,您可以随时发布自己的代码作为答案。这样,任何其他有类似问题的人都可以找到一个例子。毕竟,这就是所谓的一切。