Tkinter event for DownPress of mouse button (holding down)?

Question:

UPDATE: This seams to be a version issue. The event does not fire on click for python 3.6.1 but works on 2.7 that I have tested so far.

UPDATE: Bryan’s answer did fix my problem with the event not working correctly however the issue of the event not firing on the down-click not work is still an issue on my 3.6.1 version of python.

Python version = 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]

I am trying to write an event handler to do something repeatedly while the mouse button is being held down. I have been scouring the documentation and the internet but I cannot find any reference to just holding down the left mouse button.

Is there an event specifically for holding down the left mouse button? There is an even for release <ButtonRelease-1> but there does not seam to be one for a click and hold event.

I have tried <Button-1> and all of its synonymous events just in case but no luck. The event only fires on release but not on the down click as I want it. I don’t even need an event for constantly holding the button I just need an even for the down press only.

Documentation welcome as I can’t seam to find any.

UPDATE:

Here is an example code. It will only print when the button is released. Keep in mind I am trying to press the arrow buttons on the scroll bar and to change the speed of scrolling.

Does the scrollbar handle pressing the scroll arrows differently than a button?

import tkinter as tk


root = tk.Tk()

textbox = tk.Text(root, height = 10)
textbox.grid(row=0, column=0)

scrolling = False
yscroll = tk.Scrollbar(root, command=textbox.yview,orient="vertical", repeatinterval=10, repeatdelay=30)
textbox.configure(yscrollcommand = yscroll.set)
yscroll.grid(row=0, column=1, sticky="ns")

for i in range(1000):
    textbox.insert(tk.END, "{}n".format(i))

def scrolling_active(arrow):
    global scrolling
    root.bind('<ButtonRelease-1>', stop_scrolling())
    print(arrow)
    if scrolling == True:
        if arrow == "arrow1":
            textbox.tk.call(textbox._w,'yview', 'scroll', -100, 'units')
        if arrow == "arrow2":
            textbox.tk.call(textbox._w,'yview', 'scroll', 100, 'units')
        root.after(100, lambda a = arrow: scrolling_active(a))

def start_scrolling(event):
    global scrolling
    scrolling = True
    scrolling_active(yscroll.identify(event.x, event.y))

def stop_scrolling():
    global scrolling
    scrolling = False

yscroll.bind("<Button-1>", start_scrolling)

root.mainloop()
Asked By: Mike – SMT

||

Answers:

You should be able to bind to <ButtonPress-1> for when the Mouse is initially clicked, and then call a repeating function until <ButtonRelease-1> stops it, as you mentioned.

Answered By: SneakyTurtle

There is no event for holding a button down. There are only events for the press and release of a button.

If you need to track while a button is down, you can set a flag on the press and unset it on a release.

In your code, you have a bug. Consider this code:

root.bind('<ButtonRelease-1>', stop_scrolling())

It is functionally identical to this:

result=stop_scrolling()
root.bind('<ButtonRelease-1>', None)

To do the binding you must remove the ():

root.bind('<ButtonRelease-1>', stop_scrolling)

You also need stop_scrolling to accept the event object:

def stop_scrolling(event):
    global scrolling
    scrolling = False

Also, there’s no need to call textbox.tk.call. You can call the yview method on the tkinter object (textbox.yview("scroll", -100, "units")

Answered By: Bryan Oakley

I know it’s a bit late, but I wanted to do the exact same thing (drag an image in a canvas to make a joystick controller).

Reading the docs Events and Bindings I found this event: '<B1-Motion>'

Here’s the working example I did :

from tkinter import *

root = Tk()
root.geometry('800x600')

image1 = PhotoImage(file = 'images/button.png')
x_img,y_img = 250,250

canvas = Canvas(root, width = 500, height = 400, bg = 'white')
canvas.pack()
imageFinal = canvas.create_image(x_img, y_img, image = image1)

def move(event):
    global x_img,y_img
    x, y = event.x, event.y
    print('{}, {}'.format(x, y))
    canvas.move(imageFinal, x-x_img,y-y_img)
    x_img = x
    y_img = y
    canvas.update()

canvas.bind('<B1-Motion>', move)

root.mainloop()
Answered By: lrosique
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.