Tkinter binding question

rantingrickjohnson at gmail.com rantingrickjohnson at gmail.com
Mon Jun 18 23:51:08 EDT 2012


On Monday, June 18, 2012 1:21:02 PM UTC-5, Frederic Rentsch wrote:
> Hi All,
> 
>   For most of an afternoon I've had that stuck-in-a-dead-end feeling 
> probing to no avail all permutations formulating bindings, trying to 
> make sense of manuals and tutorials. Here are my bindings:
> 
>    label_frame.bind ('<Enter>', self.color_selected)
>    label_frame.bind ('<Leave>', self.color_selectable)
>    label_frame.bind ('<Button-1><ButtonRelease-1>', self.pick_record)
>    label_frame.bind ('<Button-3><ButtonRelease-3>', self.info_profile)

This example is useless to me. As a matter of fact, your whole explanation of the problem is ambitious at best. But you do realize that by binding both the click and release of a mouse button to the same callback you will call the callback twice? 

Try to create a simplistic and generic example of the problem. Most times you'll find the flaw. Most code should start as template that prints messages to stdout. Large applications are built by taking babysteps. Not by jumping out the fire and into the frying pan! 

WARNING: Debugging large chucks of spaghetti code is bad for your brain! Tip of the day: DIVIDE AND CONQUER!

## START CODE ##
from __future__ import print_function
import Tkinter as tk
root = tk.Tk()
root.geometry('200x200+20+20')
root.bind("<Enter>", lambda e:print("Enter"))
root.bind("<Leave>", lambda e:print("Leave"))
root.bind("<ButtonRelease-1>",
          lambda e:print("ButtonOneRelease"))
root.bind("<ButtonRelease-3>",
          lambda e:print("ButtonThreeRelease"))
root.mainloop()
## END CODE ##

Q1: Now, what exactly is the problem? Hmm???
Q2: Can you modify this code to correct the problem? Hmm???
Q3: Why are there so many inconsistencies in the Tkinter API? Hmm???

Tip: NEVER bind "ButtonClick" to trigger a callback (ESPECIALLY FOR A BUTTON CALLBACK!!!). ONLY bind "ButtonRelease". Why?  Well because if the user accidentally clicks the button, he can move his pointer beyond the boundaries of the button and then release the mouse "button" WITHOUT triggering the callback. All good GUI coders follow this design pattern. (Except in certain cases where you want a mouse click to trigger an action quickly; like a Listbox item or menu, or whatever.)

if GUI.ergonomics < optimal:
    raise NeophyteError("Do not pass GUI. Do not collect 100 dollars!")

> <Enter> and <Leave> work fine. But when I try to select an entered item, 
> the moment I push the left or the right button, color_selectable ()
> and color_selected () are called again in rapid succession. 

That does not make sense. Are you calling the method "w.update()" anywhere in the callback; or as a consequence of the callback?

> The same 
> effect happens even when I push the middle mouse button which is 
> rather weird, because it has no binding. 

Not necessarily. Many of the Tk widgets come prepackaged with annoying little default bindings that would the test the patience of a saint. Like, for example, the Tkinter.Text widget. It has a nasty little default binding to paste the cut buffer contents when you press MouseButtonTwo. And since it also has a default binding of using MouseButtonTwo+MouseMotion to scroll vertically, you find yourself inserting cut buffers everywhere!

> The behavior suggests that 
> no event can occur on an entered widget before it is left again and 
> if an event other that <Leave> comes in, the <Leave> callback gets 
> called automatically. That can't be right, though. It isn't possible 
> to click an item without entering it. 

Interesting observation. I would say your code is too complicated to properly debug. You need to divide and conquer this spaghetti mess.



More information about the Python-list mailing list