wxPython 4是否可以识别双击 same 键的方法? 特别是在我的情况下,我想知道何时快速连续按两次SHIFT键。
答案 0 :(得分:1)
这绝不像初看起来那样明显。
下面的代码使用“一次性” wx.Timer
在250毫秒后重新设置上一个密钥,以解决“快速连续”的问题。您当然可以将其设置为适当的值。
对于wxPython的旧版本,计时器没有StartOnce
选项,则必须使用Start(250, oneShot=True)
我允许使用Shift
以外的其他键来使它稍微复杂一些,并且名称字典仅用于测试目的。
我应该指出,因为这必须检查每个关键的按下状态,所以效率不是很高,但是我想您应该知道并愿意为此付出代价。
我确实有一个警告,我不知道按住某个键(例如Shift键)如何在非Linux机器上做出反应。如果事实证明它不像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的第一个问题,而且您似乎已被这些注释略微排除了。
如果您不提供代码,无法正常工作或失败,您将被否决。论坛成员喜欢查看代码,特别是您已经尝试的代码。基本上,这仅仅是一个基本指标,它表明您是否在做出单行的问题并希望其他人为您解决问题之前,已经做出自己的努力来回答问题。
我最近发布了一个自我回答的问题,该问题和答案一起发布。即使我为自己的问题提供了详细的编码答案,我也立即对此问题投了反对票。因此,请勿个人使用。我怀疑有些人只是简单地坚持“非常”遵守“规则”就可以了。
也就是说,如果您坚持使用SO一段时间并自己回答问题,您将开始看到问题和MCVE中代码的优点。您会惊讶于某些人发布的内容,期望得到答案。
答案 1 :(得分:0)
我认为问题在于,当一次触发多个键,但又又很快时,他不想被告知。我没有找到本机的方法,所以我自己尝试了。我的解决方案在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()
答案 2 :(得分:0)
这是一个更通用的解决方案
使用事件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()