[Tkinter-discuss] Unbinding Individual Events

Lion Kimbro lionkimbro at gmail.com
Thu May 10 04:19:55 CEST 2012


  Unbinding individual events from widgets has been a long standing tkinter
bug.

  I've been working on a workaround for tkhelp.py, but never really liked
the solutions I came up with.
  Most involved multiplexing from a single event receiver.

  Here is a brief demonstration:

import tkinter
global_tk = tkinter.Tk()

def tcl(tcl_code):
    """Execute tcl code string directly & return the result."""
    return global_tk.tk.eval(tcl_code)

tl = tkinter.Toplevel(name="top", width=400, height=200)
tl.title("testing")

  That's the setup frame...  Now:

>>> tl.bind('<Motion>', lambda evt:print(evt))
'37533768<lambda>'

  Moving the mouse over the toplevel, you can see the events roll in.

  Now we can look at the events in tcl:

>>> tcl('bind .top')
'<Motion>'
>>> tcl('bind .top <Motion>')
'if {"[37533768<lambda> %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X
%Y %D]" == "break"} break\n'

  The important thing to recognize is that the whole string ('if
{"[375...]" == "break"} break\n') is the binding -- NOT the individual
function item '37533768<lambda>'.

  Now if you add another binding --

>>> tl.bind("<Motion>", lambda evt:print("whoopie!"), add="+")
'37531848<lambda>'

  You can roll the mouse over, and you'll see TWO event bindings.

  Now let's look at it in detail:

>>> tcl('bind .top <Motion>')
'if {"[37533768<lambda> %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X
%Y %D]" == "break"} break\n\nif {"[37531848<l
ambda> %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y %D]" ==
"break"} break\n'

  Okay, now let's say we want to remove the first method?

  We can rebind, cutting it out.

  First, we isolate the second entry, which we want:

>>> scripts = tcl('bind .top <Motion>')
>>> scripts.split("\n")
['if {"[37533768<lambda> %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X
%Y %D]" == "break"} break', '', 'if {"[37531
848<lambda> %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y %D]" ==
"break"} break', '']
>>> s=scripts.split("\n")[-2]

  And then bind it:

>>> tcl('bind .top <Motion> {%s}' % s)
''

  You'll see the "whoopie!" printing, but the first event printer will be
gone!

  So my thought to systematize this is:

  A. Make a function (fn-A) for making a Python list out all binding
strings on a widget-sequence pair.
  B. Make a function (fn-B) that constructs the binding string for a given
function binding.
  C. Patch(/replace) widget.unbind so that it retrieves all binding strings
(via fn-A), and then removes the string that matches fn-B(funcid), and then
rebind the widget via the new list

  I think that should work.

  My main concern is that, if _tkinter does any reference counting on
function uses, then there is a memory hole.

  Thoughts?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tkinter-discuss/attachments/20120509/1988f35c/attachment-0001.html>


More information about the Tkinter-discuss mailing list