【问题标题】:check if modifier key is pressed in tkinter检查是否在 tkinter 中按下了修改键
【发布时间】:2013-11-08 14:40:25
【问题描述】:

我知道并经常使用绑定语法, 但是我怎样才能直接检查事件对象并提取两个按下的字母,例如'c' 和修饰符,例如,'Control' 和 'Alt' ?

我试过了

def reportEvent(event):
        eventDict = {
                '2': 'KeyPress', '3': 'KeyRelease', '4': 'ButtonPress', '5': 'ButtonRelease', '6': 'Motion', '7': 'Enter',
                '8': 'Leave', '9': 'FocusIn', '10': 'FocusOut', '12': 'Expose', '15': 'Visibility', '17': 'Destroy',
                '18': 'Unmap', '19': 'Map', '21': 'Reparent', '22': 'Configure', '24': 'Gravity', '26': 'Circulate',
                '28': 'Property', '32': 'Colormap','36': 'Activate', '37': 'Deactivate'}

        rpt = '\n\n%s' % (80*'=')
        rpt = '%s\nEvent: type=%s (%s)' % (rpt, event.type,eventDict.get(event.type, 'Unknown'))
        rpt = '%s\ntime=%s' % (rpt, event.time)
        rpt = '%s widget=%s' % (rpt, event.widget)
        rpt = '%s x=%d, y=%d'% (rpt, event.x, event.y)
        rpt = '%s x_root=%d, y_root=%d' % (rpt, event.x_root, event.y_root)
        rpt = '%s y_root=%d' % (rpt, event.y_root)
        rpt = '%s\nserial=%s' % (rpt, event.serial)
        rpt = '%s num=%s' % (rpt, event.num)
        rpt = '%s height=%s' % (rpt, event.height)
        rpt = '%s width=%s' % (rpt, event.width)
        rpt = '%s keysym=%s' % (rpt, event.keysym)
        rpt = '%s ksNum=%s' % (rpt, event.keysym_num)
        #### Some event types don't have these attributes
        try:
                rpt = '%s focus=%s' % (rpt, event.focus)
        except:
                try:
                        rpt = '%s send=%s' % (rpt, event.send_event)
                except:
                        pass
        print rpt

盗用 Python 和 Tkinter 编程,但它没有显示我最终按下的修饰符

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    Peter Varo's idea 的帮助下,我可以让它为我工作(运行 Windows 10 和 python 3.4)。

    from tkinter import *
    
    def onKeyDown(e):
        # The obvious information
        c = e.keysym
        s = e.state
    
        # Manual way to get the modifiers
        ctrl  = (s & 0x4) != 0
        alt   = (s & 0x8) != 0 or (s & 0x80) != 0
        shift = (s & 0x1) != 0
    
        # Merge it into an output
        # if alt:
        #     c = 'alt+' + c
        if shift:
            c = 'shift+' + c
        if ctrl:
            c = 'ctrl+' + c
        print(c)
    
    # Run the tk window
    root = Tk()
    root.bind('<Key>', onKeyDown)
    root.mainloop()
    

    alt 键在我的情况下是错误的(它总是被按下),但 ctrlshift 工作正常。

    请注意,第一次按下ctrlshift 键时,它会将其注册为主键,而不是修饰符。以后持有它只会是修饰符。

    所以您确实需要将它作为组合键来按下(例如Ctrl+a)。因此,按a 然后按ctrl 会产生一个有点奇怪的结果(它会忽略 a 并将 ctrl 标记为主键,而不是修饰符)。

    【讨论】:

      【解决方案2】:

      绑定修饰符

      以下脚本更正了先前答案中使用的不正确位标志,并考虑到 ex: state=Shift|Alt|Control 不会匹配修饰符字典中的任何内容。它需要被处理为位标志并逐位匹配。

      任何使用此功能的用户都需要考虑的是,无论您是否要求,所有 Lock 键(如果打开)都将在 event.state 中报告。例如:您打开了 CapsLock 和 NumLock 并尝试捕获 Alt + Control 〜您实际上会得到“CapsLock + NumLock + Control + Alt”。解决这个问题的最简单方法是简单地从 Modifier 字典中删除所有 ModN 键。

      据我所知,只有通过 keysym 属性才能捕获特定的 _L 和 _R 键。 state 属性将始终包含该键的通用修饰符位标志。

      #python 3.8
      from tkinter import *
      
      root = Tk()
      
      Modifier = {
          0x1    : 'Shift'        ,
          0x2    : 'CapsLock'     ,
          0x4    : 'Control'      ,
          0x8    : 'NumLock'      ,   #Mod1
          0x10   : 'Mod2'         ,   #?
          0x20   : 'ScrollLock'   ,   #Mod3
          0x40   : 'Mod4'         ,   #?
          0x80   : 'Mod5'         ,   #?
          0x100  : 'Button1'      ,
          0x200  : 'Button2'      ,
          0x400  : 'Button3'      ,
          0x800  : 'Button4'      ,
          0x1000 : 'Button5'      ,
          0x20000: 'Alt'          ,   #not a typo
      }
      
      root.bind( '<Key>', lambda e: print(' + '.join([v for k, v in Modifier.items() if k & e.state])))
      root.mainloop()
      

      绑定事件类型

      EventType 是一个枚举。创建一个重复此枚举的整个 dict 是不必要的。可以通过 event.type.name 获取 EventType 的名称,通过 event.type.value 访问值。如果您绝对必须将 Enum 克隆为 dict,则可以通过以下方式更彻底(更轻松)地完成它:

      #python 3.8
      # EventType Lookup
      BindMap = {i.name:i.value for i in EventType}
      
      # A few aliases that wont be returned from the generator
      BindMap['Key']      = '2'
      BindMap['Button']   = '4'
      BindMap['Double']   = '4'
      BindMap['Triple']   = '4'
      

      【讨论】:

        【解决方案3】:

        理论上这将是您问题的答案:

        from tkinter import *
        
        root = Tk()
        
        mods = {
            0x0001: 'Shift',
            0x0002: 'Caps Lock',
            0x0004: 'Control',
            0x0008: 'Left-hand Alt',
            0x0010: 'Num Lock',
            0x0080: 'Right-hand Alt',
            0x0100: 'Mouse button 1',
            0x0200: 'Mouse button 2',
            0x0400: 'Mouse button 3'
        }
        
        root.bind( '<Key>', lambda e: print( 'Key:', e.char,
                                             'Mods:', mods.get( e.state, None )))
        
        root.mainloop()
        

        但是,它并没有按应有的方式工作 - 或者至少它不在我的 110 键布局的匈牙利苹果键盘上..

        不管怎样,这里是事件对象的所有属性:http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/event-handlers.html

        【讨论】:

        • 这里似乎也有点不稳定(IT 键盘),但它最终是一个很好的起点。谢谢!
        • 它不是独立于操作系统的。在 Fedora 上的 Wayland 有 8200+ 个代码,在我的情况下在 windows 上是 13000+
        猜你喜欢
        • 2022-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-12
        • 2012-06-26
        • 2010-11-13
        相关资源
        最近更新 更多