简体   繁体   中英

Check if a Tkinter button remains clicked

I want to make 2 buttons (+ and -) that can change the volume. But if I want to increase the volume more, I'd like to can keep the button pressed. Any ideas how to check if a button remains pressed by the user?

def volumeUp():
    currentVolume = m.getvolume()[0]
    volumeSlider.set(currentVolume + 5)

def volumeDown():
    currentVolume = m.getvolume()[0]
    volumeSlider.set(currentVolume - 5)

volumeDownButton = Button(win, text = "-", font = myFont, command =  volumeDown, height = 1, width = 1)
volumeDownButton.pack(side = BOTTOM)

volumeUpButton = Button(win, text = "+", font = myFont, command = volumeUp,   height = 1, width = 1)
volumeUpButton.pack(side = BOTTOM)

What you can do is make the Button press fire a function that alters the volume and then schedules itself to be run again after a certain amount of time (eg 100 ms). Then when the Button is released, you can cancel the scheduled repeat of the function that alters the volume to break the loop.

I've altered your code a bit to make an example:

from tkinter import *

win = Tk()

def volumeUpPress(e=None):
    global up_after
    currentVolume = volumeSlider.get()
    volumeSlider.set(currentVolume + 2)
    up_after = win.after(100, volumeUpPress)

def volumeUpRelease(e=None):
    global up_after
    win.after_cancel(up_after)


def volumeDownPress(e=None):
    global down_after
    currentVolume = volumeSlider.get()
    volumeSlider.set(currentVolume - 2)
    down_after = win.after(100, volumeDownPress)

def volumeDownRelease(e=None):
    global down_after
    win.after_cancel(down_after)


volumeSlider = Scale(win, from_=0, to=100, orient=HORIZONTAL)
volumeSlider.pack()

volumeDownButton = Button(win, text = "-", height = 1, width = 1)
volumeDownButton.pack(side = BOTTOM)
volumeDownButton.bind("<Button-1>", volumeDownPress)
volumeDownButton.bind("<ButtonRelease-1>", volumeDownRelease)

volumeUpButton = Button(win, text = "+", height = 1, width = 1)
volumeUpButton.pack(side = BOTTOM)
volumeUpButton.bind("<Button-1>", volumeUpPress)
volumeUpButton.bind("<ButtonRelease-1>", volumeUpRelease)

win.mainloop()

Things to note:

  • I didn't use the Button's command since that doesn't give you the flexibility of knowing when the Button is released. Instead I made two binds, one for when the Button is pressed, one for when it is released.
  • I use the after method to schedule a new call to the same function after a set number of milliseconds, I save a reference to this scheduled function in a global variabel, to be able to use it again in the release function to cancel it with after_cancel
  • .bind calls functions with an event object, while after calls a function without arguments, because both call the same function, I made it so that the function can be called both with and without argument ( e=None )

An alternative to fhdrsdg's answer that also uses after would be to measure the state value of the Button and detect whether it is currently active , to do this we bind a function to the Button which checks the state and then increments a value if the state is active before using after to call the function again after a short delay:

from tkinter import *

class App():
    def __init__(self, root):
        self.root = root
        self.button = Button(self.root, text="Increment")

        self.value = 0

        self.button.pack()
        self.button.bind("<Button-1>", lambda x: self.root.after(10, self.increment))

    def increment(self, *args):
        if self.button["state"] == "active":
            self.value += 1
            print(self.value)
            self.root.after(10, self.increment)

root = Tk()
App(root)
root.mainloop()

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