【问题标题】:Group events in wxPythonwxPython 中的组事件
【发布时间】:2019-08-26 08:40:51
【问题描述】:

我想在 wxPython 中处理两个事件。具体来说,我想将ON_KEY_DOWNCHAR 事件分组以调用一个方法,其中包含有关按下的键以及该字符会产生什么(如果有的话)的信息。

引用文档:

虽然这两个函数都可以与 wxEVT_KEY_DOWN 、 wxEVT_KEY_UP 和 wxEVT_CHAR 类型的事件一起使用,但它们返回的值对于前两个事件和最后一个事件是不同的。对于后者,返回的键对应于将出现的字符,例如如果用户按下其中的键,则为文本区域。因此,它的值取决于 Shift 键的当前状态,对于字母,取决于 Caps Lock 修饰符的状态。例如,如果在没有按住 Shift 的情况下按下 A 键,则为该键按下生成的 wxEVT_CHAR 类型的 wx.KeyEvent 将返回(来自 GetKeyCode 或 GetUnicodeKey,因为它们的含义与 ASCII 字符一致)对应于 ASCII 值的 97 键码一种 。如果按下相同的键但按住 Shift(或 Caps Lock 处于活动状态),则该键可能是 65,即大写 A 的 ASCII 值。然而,对于按键向下和向上事件,返回的按键代码将改为 A,与修饰键的状态无关,即它仅取决于按下的物理键,并且不会使用当前键盘状态转换为其逻辑表示。

问题是我想同时拥有这两个信息。如果按下某个键,我希望生成诸如 KEY_UP 或 KLEY_DOWN 之类的“原始键代码”,并且键入的字符(如果有)对应。我试图想出一个解决方案。但是CHAR 并不是一直被提出来的(有些按键不会产生任何字符)。

文档给出了 shift 和 CapLock 的例子,这有点奇怪。但是,请考虑并非所有用户都有 QWERTY 键盘。这更有意义:如果使用 AZERTY 键盘的用户按下与 QWERTY 中第一个数字对应的字母,则将写入 &(KEY_DOWN.KeyCode 将产生'1',而CHAR.KeyCode 将产生& . 更有意义吗?

那么如何拦截这两个事件并使用这两种信息调用一个和一个方法(要理解CHAR 不会总是被引发)?

我以为我找到了解决方案:如果我可以访问事件循环或事件处理程序的事件队列,也许我可以检查:如果引发了 KEY_DOWN 事件,那么我检查下一个事件是否是 @ 987654329@,如果是,则从CHAR 检索所需信息并调用单个方法。但是我不知道该怎么做,并且文档没有(据我所知)准确描述何时引发CHAR 事件(它可能不完全在KEY_DOWN 之后,它可能就在之前KEU_UP 或其他地方的父亲)。

另一种可能性是“强制”wx 将KEY_DOWN 事件“转换”为CHAR 事件。同样,这听起来很具体,我找不到如何做到这一点。总而言之,我需要将“原始键码”转换为系统“键入字符”,我也不需要完整的事件。

代码示例

显然,我不会编写代码,但这是我想要实现的一个小例子:

import wx

class TestPanel(wx.Panel):

    def __init__(self, parent):
        super().__init__(parent)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.label = wx.StaticText(self, label="Type something here")
        self.text = wx.TextCtrl(self)
        self.sizer.Add(self.label)
        self.sizer.Add(self.text)
        self.SetSizerAndFit(self.sizer)

        # Binding isn't possible
        #self.text.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)

    def OnKeyDown(self, keycode, unicode=None):
        """
        The `keycode` key was pressed.

        It generated (if anything) the `unicode` character.

        """
        print(f"The {key_code} was pressed, generating the {unicode} character.")

app = wx.App()
frame = wx.Frame(None)
panel = TestPanel(frame)
frame.Show()
app.MainLoop()

这里的挑战是将文本字段连接到 OnKeyDown 方法,以同时传输密钥代码和 unicode 密钥。 (EVT_KEY_DOWN 上的 GetUnincodeKey() 不起作用,它严格等同于 key_code,但对我没有帮助)。

回顾一下,如果你按键盘上的 a,key_code 应该是 65(大写 A)而 unicode 应该是 97(小写 a),除非 caplock 已打开。如果您使用的布局与 QWERTY 不同,则 unicode 应该始终是出现在文本中的字母(并且此信息仅在 CHAR 事件中给出)。希望澄清!

【问题讨论】:

    标签: python wxpython


    【解决方案1】:

    如果没有代码,有时很难想象您正在尝试做什么。
    我认为你缺少的是event.Skip()

    Skip()

    此方法可以在事件处理程序中使用,以控制是否在当前事件返回后调用绑定到此事件的其他事件处理程序 如果没有 Skip(或等效地,如果使用 Skip(false)),将不再处理该事件。如果调用了 Skip(true),则事件处理系统会继续为该事件寻找下一个处理函数,即使它已经在当前处理程序中处理过。

    另外,来自文档:

    获取UnicodeKey(自己) 返回此按键事件对应的 Unicode 字符。

    如果按下的键没有任何字符值(例如光标键),此方法将返回 WXK_NONE 。在这种情况下,您应该使用 GetKeyCode 来检索键的值。

    所以我们可以将以下内容绑定到 KEY_DOWN、KEY_UP 和 CHAR:

    def EvtKey(self, event):
        if event.GetUnicodeKey():
            print("A value key")
            print(chr(event.GetUnicodeKey()))
        else:
            print("a key event")
            print(event.GetKeyCode())
        event.Skip()
    

    根据您的评论进行编辑: 我建议你看看EVT_CHAREVT_CHAR_HOOK

    import wx
    
    class TestPanel(wx.Panel):
    
        def __init__(self, parent):
            super().__init__(parent)
            self.sizer = wx.BoxSizer(wx.VERTICAL)
            self.label = wx.StaticText(self, label="Type something here")
            self.text = wx.TextCtrl(self)
            self.sizer.Add(self.label)
            self.sizer.Add(self.text)
            self.SetSizerAndFit(self.sizer)
    
            self.text.Bind(wx.EVT_CHAR, self.OnKeyDown)
            # The choice here will depend on exactly what you want
            # CHAR_HOOK will additionally give shift, ctrl, alt etc
            #self.text.Bind(wx.EVT_CHAR_HOOK, self.OnKeyDown)
    
        def OnKeyDown(self, event):
            key_code = event.GetUnicodeKey()
            control_key = event.GetKeyCode()
            if key_code == 0:
                print(f"The control key {control_key} was pressed.")
            else:
                unicode = chr(key_code)
                """
                The `keycode` key was pressed.
    
                It generated (if anything) the `unicode` character.
    
                """
                print(f"The {key_code} was pressed, generating the {unicode} character.")
            event.Skip()
    
    app = wx.App()
    frame = wx.Frame(None)
    panel = TestPanel(frame)
    frame.Show()
    app.MainLoop()
    

    【讨论】:

    • 感谢您的回答。不幸的是,它不能解决我的问题。我添加了一个不完整的代码示例,希望有助于展示我想要实现的目标。
    • @vincent-lg 我添加了一个替代我原来的答案
    • 非常感谢。我不知道这个事件甚至存在。我想我需要帮助来浏览 wxPython 的文档。我不确定它对我有用,但这似乎比我考虑的要容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 2014-12-08
    • 2017-11-05
    • 2017-09-07
    • 1970-01-01
    相关资源
    最近更新 更多