简体   繁体   中英

How to press more than one tkinter button simultaneously using python

I have multiple buttons in tkinter window, but on a computer we only have one mouse pointer at one location at a time, how can I multi-press buttons simultaneously just like on a touch screen?

Here is a sample code of what I am trying to do,

#!/usr/bin/python
import Tkinter as Tk

def button_pressed_cb(event):
    print("You pressed " + event.widget['text'])

def button_release_cb(event):
    print("You released " + event.widget['text'])

root = Tk.Tk()
button1 = Tk.Button(root, text="button1")
button1.pack()
button2 = Tk.Button(root, text="button2")
button2.pack()

button1.bind("<ButtonPress>", button_pressed_cb)
button1.bind("<ButtonRelease>", button_release_cb)
button2.bind("<ButtonPress>", button_pressed_cb)
button2.bind("<ButtonRelease>", button_release_cb)

root.mainloop()

After executing this, I get a sample output of something like this,

You pressed button1
You released button1
You pressed button2
You released button2

What I want to achieve is to be able to generate events which occur in this sequence,

You pressed button1
You pressed button2
You released button2
You released button1

Does anybody know what's the best way to achieve this? Thank you so much.

If you just want to call the callbacks, you can do that—they're ordinary Python functions, after all.

If you're asking how to create an event and dispatch it, you can use the event_generate method. Unfortunately, I don't know of any tkinter documentation for this, so you have to look at the Tcl/Tk docs instead. But the basic idea is:

def hit_the_buttons():
    button1.event_generate('<ButtonPress>', when='tail')
    button2.event_generate('<ButtonPress>', when='tail')
    button2.event_generate('<ButtonRelease>', when='tail')
    button1.event_generate('<ButtonRelease>', when='tail')

The when argument puts the events at the end of the event queue rather than processing them immediately, so they won't interfere with things like redraws or actual mouse events. It isn't really necessary here; I included it mainly to show how to map one of those Tcl arguments ( -when tail ) to tkinter.

If you want this to go through the normal dispatch instead of directly to the buttons, you can call root.event_generate and pass x and y arguments that will hit-test as inside the buttons.

Ok, I found a solution. I put in extra checks that if user presses and holds ctrl before clicking a button, that button will latch on to that pressed state. Then user can go and click other button etc. User can click that button again to unlatch it.

I also added a hover message as well for user to tell the user they can use ctrl to latch a button and achieve multikey presses.

Here is the new code,

#!/usr/bin/python
import Tkinter as Tk

class HoverInfo(Tk.Menu):
    def __init__(self, parent, text):
        Tk.Menu.__init__(self, parent, tearoff=0, 
                         background='light goldenrod yellow')

        self.__displayed = False
        for line in text.split('\n'):
            self.add_command(label=line)

        parent.bind("<Enter>", self.__display)
        parent.bind("<Leave>", self.__remove)

    def __display(self, event):
        if event.widget['state'] == Tk.NORMAL:
            if not self.__displayed:
                self.__displayed = True
                self.post(event.x_root+5, event.y_root+5)

    def __remove(self, event):
        if self.__displayed:
            self.__displayed = False
            self.unpost()

CONTROL = 4

def button_pressed_cb(event):
    if event.widget['state'] != Tk.DISABLED:
        print("You pressed " + event.widget['text'])
        if (event.state & CONTROL) == CONTROL:
            event.widget.config(state=Tk.DISABLED)
            event.widget.config(relief=Tk.SUNKEN)

def button_release_cb(event):
    if (event.state & CONTROL) != CONTROL:
        print("You released " + event.widget['text'])
        event.widget.config(state=Tk.NORMAL)
        event.widget.config(relief=Tk.RAISED)


root = Tk.Tk()
button1 = Tk.Button(root, text="button1")
button1.pack()
button2 = Tk.Button(root, text="button2")
button2.pack()

button1.bind("<ButtonPress>", button_pressed_cb)
button1.bind("<ButtonRelease>", button_release_cb)
button2.bind("<ButtonPress>", button_pressed_cb)
button2.bind("<ButtonRelease>", button_release_cb)

HoverInfo(button1, "Hint:\nYou can hold Ctrl key before\nclicking a button to latch it.")

root.mainloop()

Now, this is how the hover message looks, https://ibb.co/dEb6Bn

And when user holds ctrl key and clicks button 1 and then button 2, then this is how it looks, https://ibb.co/eVzRBn

Now, I can easily generate this sequence of events,

You pressed button1
You pressed button2
You released button2
You released button1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM