Multiple Key Event Bindings in Tkinter - “Control + E” “Command (apple) + E” etc

后端 未结 4 1200
鱼传尺愫
鱼传尺愫 2020-12-20 13:22

Mac OS X 10.6.6 - Tkinter

I want to bind multiple-key events, and while I have found an effbot article and the Tk man pages, I\'ve been unable to make this work corr

4条回答
  •  悲&欢浪女
    2020-12-20 13:38

    Option 1

    Something like this:

    # Status of control, shift and control+shift keys in Python
    import tkinter as tk
    
    ctrl = False
    shift = False
    ctrl_shift = False
    
    def key(event):
        global ctrl, shift, ctrl_shift
        #print(event.keycode, event.keysym, event.state)
        if ctrl_shift:
            print('++{}'.format(event.keysym))
        elif ctrl:
            print('+{}'.format(event.keysym))
        elif shift:
            print('+{}'.format(event.keysym))
        ctrl = False
        shift = False
        ctrl_shift = False
    
    def control_key(state, event=None):
        ''' Controll button is pressed or released '''
        global ctrl
        ctrl = state
    
    def shift_key(state, event=None):
        ''' Controll button is pressed or released '''
        global shift
        shift = state
        control_shift(state)
    
    def control_shift(state):
        ''' + buttons are pressed or released '''
        global ctrl, ctrl_shift
        if ctrl == True and state == True:
            ctrl_shift = True
        else:
            ctrl_shift = False
    
    root = tk.Tk()
    root.geometry('256x256+0+0')
    
    root.event_add('<>',  '',   '')
    root.event_add('<>', '', '')
    root.event_add('<>',    '',     '')
    root.event_add('<>',   '',   '')
    
    root.bind('<>', lambda e: control_key(True))
    root.bind('<>', lambda e: control_key(False))
    root.bind('<>', lambda e: shift_key(True))
    root.bind('<>', lambda e: shift_key(False))
    root.bind('', key)
    
    root.mainloop()
    

    Option 2

    However, in the end, I decided to process keystrokes manually. You can se the example in this file. First, I set keycodes and shortcuts in two dictionaries self.keycode and self.__shortcuts:

    # List of shortcuts in the following format: [name, keycode, function]
    self.keycode = {}  # init key codes
    if os.name == 'nt':  # Windows OS
        self.keycode = {
            'o': 79,
            'w': 87,
            'r': 82,
            'q': 81,
            'h': 72,
            's': 83,
            'a': 65,
        }
    else:  # Linux OS
        self.keycode = {
            'o': 32,
            'w': 25,
            'r': 27,
            'q': 24,
            'h': 43,
            's': 39,
            'a': 38,
         }
    self.__shortcuts = [['Ctrl+O', self.keycode['o'], self.__open_image],   # 0 open image
                        ['Ctrl+W', self.keycode['w'], self.__close_image],  # 1 close image
                        ['Ctrl+R', self.keycode['r'], self.__roll],         # 2 rolling window
                        ['Ctrl+Q', self.keycode['q'], self.__toggle_poly],  # 3 toggle between roi/hole drawing
                        ['Ctrl+H', self.keycode['h'], self.__open_poly],    # 4 open polygons for the image
                        ['Ctrl+S', self.keycode['s'], self.__save_poly],    # 5 save polygons of the image
                        ['Ctrl+A', self.keycode['a'], self.__show_rect]]    # 6 show rolling window rectangle
    

    Then added self.__keystroke function to monitor keystroke events. This function checks if key is pressed or not:

    def __keystroke(self, event):
        """ Language independent handle events from the keyboard """
        #print(event.keycode, event.keysym, event.state)  # uncomment it for debug purposes
        if event.state - self.__previous_state == 4:  # check if  key is pressed
            for shortcut in self.__shortcuts:
                if event.keycode == shortcut[1]:
                    shortcut[2]()
        else:  # remember previous state of the event
            self.__previous_state = event.state
    

    Finally, bind the self.__keystroke function to the master GUI window. Note that this function is bonded in the idle mode, because multiple keystrokes slow down the program on weak computers:

    # Handle keystrokes in the idle mode, because program slows down on a weak computers,
    # when too many key stroke events in the same time.
    self.master.bind('', lambda event: self.master.after_idle(self.__keystroke, event))
    

提交回复
热议问题