Python Forum
[Tkinter] Mouse click without use bind
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Mouse click without use bind
#1
I have code with bind which I do not like.
is there another way than bind?
I am looking for counting when the mouse or touchscreen is pressed and hold for about 3 seconds to respond.
Thanks!
Reply
#2
There is no built-in way to handle Drag and drop, and the only way to do this is to create the functionality yourself.

Quote:is there another way than bind?

The only possible way to do this without bind is to create a low level listener (and this is essentially a home-grown bind), and you don't want to go there unless you thoroughly understand the interrupt process. Bind is a way to capture interrupts within your code, and you need not be afraid of them.

for drag and drop, you need to bind:
  • Button press (In tkinter this looks like <ButtonPress-1> )
  • Button move (In tkinter this looks like <B1-Motion> )
  • Button release (In tkinter this looks like <ButtonRelease-1>
It is not normal, nor needed to time the release, it's captured with the mouse up interrupt.

There are many examples of how to do this. It's quite simple to create your own,
you need create hooks for start, move and, stop activity.

Do a google search for: 'drag and drop for tkinter'

Please not that there is DRag and Drop support comming in ptrhon release 3.9.0 see: https://docs.python.org/3.9/library/tkinter.dnd.html
expected release in just 4 days (Oct 5) or you can download and install the release
see: https://pythoninsider.blogspot.com/2020/...Insider%29

you can find the code for this

if you can't find a suitable example with google,
come back, post your code, and I or another mod/admin will help you write one.

Finally: Perhaps it's time to consider my favorite wxpython, Kivy, or Qt5
Reply
#3
Where is drag and drop mentioned?

If you want to force a 3 second continuous touch before doing some action, you'll need to at least bind to touch and release and use an after to call your eventual callback.
from tkinter import *
after_id = None
root = Tk()

def press_cb(event):
    global after_id
    after_id = root.after(3000, after_cb)

def release_cb(event):
    global after_id
    if after_id is not None:
        root.after_cancel(after_id)
        after_id = None

def after_cb():
    """Do whatever"""
    print('Leg go of me!!')

root.bind('<ButtonPress-1>', press_cb)
root.bind('<ButtonRelease-1>', release_cb)
Or you could combine a few things.
from tkinter import *

root = Tk()

def press_cb(event=None):
    global lp_id
    if event is None:
        print('Let go my Eggo!')
        lp_id = None
    elif event.type == EventType.ButtonPress:
        lp_id = root.after(3000, press_cb)
    elif lp_id:
        root.after_cancel(lp_id)
        lp_id = None

root.bind('<ButtonPress-1>', press_cb)
root.bind('<ButtonRelease-1>', press_cb)
It would be useful to know what you are trying to do, what you have tried to do, and why you are unhappy with what you've done. At least I am confused about what you are asking.
Reply
#4
Quote:deanhystad asked: Where is drag and drop mentioned?
Somehow, I answered to the wrong thread.
Now I have to find the correct one, and move the post.
Reply
#5
Thanks for this and I am sorry for I missed to explained, I do not discuss about drag and drop. I talk about like press button and hold that's it.
Like when I press and hold for 3 sec then open the menu.

thanks again!

Let say for example:

if mousepress == 1:
    count = count + 1
else:
    count = 0

if count > 10 and count < 20:
    Print("Still holding")

if count > 50 and count < 60:
    print("That's enough!")

if count > 100:
    Print ("Fine! I am quitting!")
    exit()

The bind do not to continue to pass when press and hold.
Reply
#6
No one can?
Reply
#7
I provided an example of how you can use bind to execute a delayed event. The mouse does not do hold/repeat like the keyboard, and even if it did, counting is a poor way to measure time.
Reply
#8
here's my attempt:
from tkinter import *

import logging, sys
from time import strftime as s_time, localtime as l_time, time
logging.basicConfig(level= logging.DEBUG)
#logging.disable(logging.CRITICAL)

class Long_Key_Press(Frame):
    def __init__(self, parent=None, HOLD_TIME=10):
        self.parent= parent
        self.HOLD_TIME= HOLD_TIME
        Frame.__init__(self, self.parent)
        self.pack(expand=YES, fill=BOTH)
        
        self.canvas= Canvas(self)
        self.canvas.config(width= 500, height= 700, bg='skyblue')
        self.canvas.pack(expand=YES, fill=BOTH)
        
        self.btn= Button(self.canvas, text='QUIT', command= self.get_entry)
        self.btn.place(x=400,y=600)
        
        self.time_txt= StringVar()
        self.lbl_1= Label(self.canvas, textvariable= self.time_txt,
                          font=('arial',25,'bold'))
        self.lbl_1.place(x=20,y=50)

        self.output_lbl= StringVar()
        self.lbl_2= Label(self.canvas, textvariable= self.output_lbl,
                          font=('arial',25,'bold'))
        self.lbl_2.place(x=20,y=200)
        self.output_lbl.set('Hold left mouse down')
        
        self.bind_all('<Key>', self.key)
        self.canvas.bind('<Button-1>', self.left_mouse_down)
        self.canvas.bind('<ButtonRelease-1>', self.left_mouse_up)

        self.time_elapsed= 0.0
        
        self.counter= 0
        self.g_count=0
    def set_timer(self,elapsed):
        self.minutes= int(elapsed/60)
        self.seconds= int(elapsed- self.minutes*60.0)
        self.hseconds= int((elapsed- self.minutes*60.0 - self.seconds)*100)
        self.time_txt.set('%02d:%02d:%02d'%(self.minutes,
                                            self.seconds,
                                            self.hseconds))
    def update_time(self):
        self.time_elapsed= time() - self.start
        self.set_timer(self.time_elapsed)
        if self.seconds == self.HOLD_TIME * .25:
            self.output_lbl.set('Quarter way there...')
        elif self.seconds == self.HOLD_TIME * .5:
            self.output_lbl.set('Half way there...')
        elif self.seconds == self.HOLD_TIME * .75:
            self.output_lbl.set("3/4 the to finish...")
        elif self.seconds >= self.HOLD_TIME:
            self.output_lbl.set('One second longer....')
        
        self._timer= self.after(50, self.update_time)
    def left_mouse_down(self, event):
        x,y= event.x, event.y
        self.start= time() - self.time_elapsed
        self.update_time()
        
    def left_mouse_up(self, event):
        self.after_cancel(self._timer)
        self.time_elapsed= 0.0
        
        if self.seconds > self.HOLD_TIME:
            self.output_lbl.set("That is long enough.")
            self.canvas.config(bg='lime')
        else:
            self.output_lbl.set("Longer hold is required.")
            self.canvas.config(bg='red')
        
        
    def key(self, event):
        self.g_count +=1
        message= 'count:{0} key:{1} num:{2} state:{3}'.format(self.g_count,
                                                 event.keysym,event.keysym_num,
                                       event.state)
        logging.debug(message)
        
    def get_entry(self):
        self.parent.destroy()
if __name__ == '__main__':
    root= Tk()
    Long_Key_Press(root, HOLD_TIME=20)
    root.mainloop()

ATARI_LIVE likes this post
Reply
#9
(Oct-21-2020, 03:08 PM)joe_momma Wrote: here's my attempt:
from tkinter import *

import logging, sys
from time import strftime as s_time, localtime as l_time, time
logging.basicConfig(level= logging.DEBUG)
#logging.disable(logging.CRITICAL)

class Long_Key_Press(Frame):
    def __init__(self, parent=None, HOLD_TIME=10):
        self.parent= parent
        self.HOLD_TIME= HOLD_TIME
        Frame.__init__(self, self.parent)
        self.pack(expand=YES, fill=BOTH)
        
        self.canvas= Canvas(self)
        self.canvas.config(width= 500, height= 700, bg='skyblue')
        self.canvas.pack(expand=YES, fill=BOTH)
        
        self.btn= Button(self.canvas, text='QUIT', command= self.get_entry)
        self.btn.place(x=400,y=600)
        
        self.time_txt= StringVar()
        self.lbl_1= Label(self.canvas, textvariable= self.time_txt,
                          font=('arial',25,'bold'))
        self.lbl_1.place(x=20,y=50)

        self.output_lbl= StringVar()
        self.lbl_2= Label(self.canvas, textvariable= self.output_lbl,
                          font=('arial',25,'bold'))
        self.lbl_2.place(x=20,y=200)
        self.output_lbl.set('Hold left mouse down')
        
        self.bind_all('<Key>', self.key)
        self.canvas.bind('<Button-1>', self.left_mouse_down)
        self.canvas.bind('<ButtonRelease-1>', self.left_mouse_up)

        self.time_elapsed= 0.0
        
        self.counter= 0
        self.g_count=0
    def set_timer(self,elapsed):
        self.minutes= int(elapsed/60)
        self.seconds= int(elapsed- self.minutes*60.0)
        self.hseconds= int((elapsed- self.minutes*60.0 - self.seconds)*100)
        self.time_txt.set('%02d:%02d:%02d'%(self.minutes,
                                            self.seconds,
                                            self.hseconds))
    def update_time(self):
        self.time_elapsed= time() - self.start
        self.set_timer(self.time_elapsed)
        if self.seconds == self.HOLD_TIME * .25:
            self.output_lbl.set('Quarter way there...')
        elif self.seconds == self.HOLD_TIME * .5:
            self.output_lbl.set('Half way there...')
        elif self.seconds == self.HOLD_TIME * .75:
            self.output_lbl.set("3/4 the to finish...")
        elif self.seconds >= self.HOLD_TIME:
            self.output_lbl.set('One second longer....')
        
        self._timer= self.after(50, self.update_time)
    def left_mouse_down(self, event):
        x,y= event.x, event.y
        self.start= time() - self.time_elapsed
        self.update_time()
        
    def left_mouse_up(self, event):
        self.after_cancel(self._timer)
        self.time_elapsed= 0.0
        
        if self.seconds > self.HOLD_TIME:
            self.output_lbl.set("That is long enough.")
            self.canvas.config(bg='lime')
        else:
            self.output_lbl.set("Longer hold is required.")
            self.canvas.config(bg='red')
        
        
    def key(self, event):
        self.g_count +=1
        message= 'count:{0} key:{1} num:{2} state:{3}'.format(self.g_count,
                                                 event.keysym,event.keysym_num,
                                       event.state)
        logging.debug(message)
        
    def get_entry(self):
        self.parent.destroy()
if __name__ == '__main__':
    root= Tk()
    Long_Key_Press(root, HOLD_TIME=20)
    root.mainloop()


That's works but almost!... not for me. I really thankful for this.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] program unresponsive during pynput mouse click RobotTech 1 676 May-07-2020, 04:43 PM
Last Post: RobotTech
  [Kivy] AttributeError: 'NoneType' object has no attribute 'bind' faszination_92 2 1,042 Apr-12-2020, 07:01 PM
Last Post: Larz60+
  [WxPython] Bind error PeterLinux 1 612 Apr-06-2020, 03:07 AM
Last Post: joe_momma
  Tkinter:Unable to bind and unbind function with a button shallanq 2 721 Mar-28-2020, 02:05 AM
Last Post: joe_momma
  [Tkinter] Mouse click event not working on multiple tkinter window evrydaywannabe 2 1,001 Dec-16-2019, 04:47 AM
Last Post: woooee
  [Tkinter] How to bind an event when enter is pressed on a Entry control? Michael4 4 1,081 Aug-29-2019, 10:11 PM
Last Post: Michael4
  [PySimpleGui] How to alter mouse click button of a standard submit button? skyerosebud 3 1,282 Jul-21-2019, 06:02 PM
Last Post: FullOfHelp
  [PyQt] `QPushButton` without mouse click animation Atalanttore 2 2,013 Apr-22-2019, 01:00 PM
Last Post: Atalanttore
  Update plot by <Return> bind with entry widget Zorro 1 1,375 Mar-09-2019, 12:27 PM
Last Post: Zorro
  QTabBar Indexing is wrong for right mouse click xenas 2 931 Jan-04-2019, 10:08 PM
Last Post: xenas

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020