Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Tkinter unbinding

Reply
Thread Tools

Tkinter unbinding

 
 
r
Guest
Posts: n/a
 
      12-18-2008
On Dec 18, 1:48*pm, Roger <(E-Mail Removed)> wrote:
> On Dec 18, 12:49*pm, r <(E-Mail Removed)> wrote:
>
> > Maybe someone will chime in with an answer, sorry i could not help.
> > ponder this, i must...

>
> Regardless, thanks for your help! I truly appreciate it.
>
> Roger.


'no problema mi amigo!'.to_english(no problem my friend!)
 
Reply With Quote
 
 
 
 
Bad Mutha Hubbard
Guest
Posts: n/a
 
      12-19-2008
Roger wrote:

> I've done a lot of googling for this topic and I fear that it's not
> possible. I have a widget that is overloaded with several bindings.
> I want to be able to unbind one method form the same Event without
> destroying all the other bindings to the same event that's associated
> to the same widget.
>
> For example:
>
> import Tkinter
>
> def test():
> print 'test'
>
> def test2():
> print 'test2'
>
> root = Tkinter.Tk()
> funcid1 = root.bind("<1>", lambda e: test())
> funcid2 = root.bind("<1>", lambda e: test2(), add='+')
> root.unbind("<1>", funcid2)
> root.mainloop()
>
> When run neither <1> binding will exist against the root because the
> unbind will unbind all the functions associated with that event.
> However, in this example, I only want to unbind test2 not test1.
>
> Any help is greatly appreciated. Thanks!
> Roger.


I believe you've discovered a bug. Aside from recommending trying
wxWidgets, here's the source of the unbind function in Tkinter.py:

def unbind(self, sequence, funcid=None):
"""Unbind for this widget for event SEQUENCE the
function identified with FUNCID."""
self.tk.call('bind', self._w, sequence, '')
if funcid:
self.deletecommand(funcid)

-------------------------------------------
First, it replaces all bindings for the sequence with the empty string,
i.e., it deletes all bindings for that event unconditionally. THEN it
calls deletecommand() with the funcid, who knows what that does. My Tcl
is not so sharp.
I have an idea for a workaround, let me see if it works...
-Chuckk

 
Reply With Quote
 
 
 
 
Bad Mutha Hubbard
Guest
Posts: n/a
 
      12-19-2008
Bad Mutha Hubbard wrote:

> Roger wrote:
>
>> I've done a lot of googling for this topic and I fear that it's not
>> possible. I have a widget that is overloaded with several bindings.
>> I want to be able to unbind one method form the same Event without
>> destroying all the other bindings to the same event that's associated
>> to the same widget.
>>
>> For example:
>>
>> import Tkinter
>>
>> def test():
>> print 'test'
>>
>> def test2():
>> print 'test2'
>>
>> root = Tkinter.Tk()
>> funcid1 = root.bind("<1>", lambda e: test())
>> funcid2 = root.bind("<1>", lambda e: test2(), add='+')
>> root.unbind("<1>", funcid2)
>> root.mainloop()
>>
>> When run neither <1> binding will exist against the root because the
>> unbind will unbind all the functions associated with that event.
>> However, in this example, I only want to unbind test2 not test1.
>>
>> Any help is greatly appreciated. Thanks!
>> Roger.

>
> I believe you've discovered a bug. Aside from recommending trying
> wxWidgets, here's the source of the unbind function in Tkinter.py:
>
> def unbind(self, sequence, funcid=None):
> """Unbind for this widget for event SEQUENCE the
> function identified with FUNCID."""
> self.tk.call('bind', self._w, sequence, '')
> if funcid:
> self.deletecommand(funcid)
>
> -------------------------------------------
> First, it replaces all bindings for the sequence with the empty string,
> i.e., it deletes all bindings for that event unconditionally. THEN it
> calls deletecommand() with the funcid, who knows what that does. My Tcl
> is not so sharp.
> I have an idea for a workaround, let me see if it works...
> -Chuckk


Alas, my workaround doesn't work either. Tkinter.py also states that
calling bind with only an event sequence will return all bindings for
that sequence; I was thinking I could then remove the function in
question from that list and call bind again with each of the
functions in the remaning list as argument. I had
high hopes. The return value of calling bind with no target function
is just about Tcl nonsense:

#!/usr/bin/env python

import Tkinter

def test(event):
print 'test'

def test2(event):
print 'test2'

root = Tkinter.Tk()
funcid1 = root.bind("<1>", test)
funcid2 = root.bind("<1>", test2, add='+')
print funcid1, funcid2

bound = root.bind('<Button-1>')
print "bound:", bound
#root.unbind("<1>", funcid=funcid2)
root.mainloop()

---------------------------
Note that I took out the lambdas and gave event arguments to the
functions; if you did that on purpose, because you need to call the same
functions without events, then just ignore that...
SO, the other workaround, which I've used, is to bind the event to a
generic function, and have that generic function conditionally call
the functions you want. I'll go back and try to make an example from
your example. -Chuckk
 
Reply With Quote
 
Roger
Guest
Posts: n/a
 
      12-19-2008
> Note that I took out the lambdas and gave event arguments to the
> functions; if you did that on purpose, because you need to call the same
> functions without events, then just ignore that...
> SO, the other workaround, which I've used, is to bind the event to a
> generic function, and have that generic function conditionally call
> the functions you want. I'll go back and try to make an example from
> your example. -Chuckk


Thanks Chuckk! You've done exactly what I did so far. I went through
the source in Tkinter.py and had an inkling of what the unbind
function was doing. I believe, and please correct me if I'm wrong,
in: self.tk.call('bind', self._w, sequence, '') , the '' is unbinding
all methods and I believe the self.deletecommand(funcid) is a
workaround for a memory leak otherwise. Perhaps self.tk.call('bind',
self._w, sequence, funcid) would work but that's a pure guess. I
would have liked to investigate the tcl source directly to see if I
could develop a workaround through a tk.call() but that was hitting a
wall in terms of any documentation I could research. I'm interested
in any workaround you may have however!

You now, I really considered going over to wxwidgets, and I definitely
want to try it after the current app I'm developing is complete, but
I've so much experience with Tkinter now after banging my head against
a wall for months (productive months mind you) on various projects,
it's like an old persnickety friend you just can't give up. =)

Thanks a ton!
Roger.
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      12-19-2008
Roger wrote:

>> Note that I took out the lambdas and gave event arguments to the
>> functions; if you did that on purpose, because you need to call the same
>> functions without events, then just ignore that...
>> SO, the other workaround, which I've used, is to bind the event to a
>> generic function, and have that generic function conditionally call
>> the functions you want. I'll go back and try to make an example from
>> your example. -Chuckk

>
> Thanks Chuckk! You've done exactly what I did so far. I went through
> the source in Tkinter.py and had an inkling of what the unbind
> function was doing. I believe, and please correct me if I'm wrong,
> in: self.tk.call('bind', self._w, sequence, '') , the '' is unbinding
> all methods and I believe the self.deletecommand(funcid) is a
> workaround for a memory leak otherwise. Perhaps self.tk.call('bind',
> self._w, sequence, funcid) would work but that's a pure guess. I
> would have liked to investigate the tcl source directly to see if I
> could develop a workaround through a tk.call() but that was hitting a
> wall in terms of any documentation I could research. I'm interested
> in any workaround you may have however!


The documentation for bind in tcl is here

http://www.tcl.tk/man/tcl8.4/TkCmd/bind.htm

and as far as I understand it doesnt support unbinding selected callbacks,
either. I'd suggest a plain-python workaround along the lines of

import Tkinter

def test(event):
print 'test'

def test2(event):
print 'test2'

root = Tkinter.Tk()
root.geometry("200x100+100+100")

class Multiplexer:
def __init__(self):
self.funcs = []
def __call__(self, event):
for f in self.funcs:
f(event)
def add(self, f):
self.funcs.append(f)
return f
def remove(self, f):
self.funcs.remove(f)

m = Multiplexer()
m.add(test)
m.add(test2)
root.bind("<1>", m)

def unbind():
print "unbind"
m.remove(test2)

button = Tkinter.Button(root, text="unbind test2", command=unbind)
button.pack()

root.mainloop()

Peter
 
Reply With Quote
 
Roger
Guest
Posts: n/a
 
      12-19-2008
> either. I'd suggest a plain-python workaround along the lines of

Wow. You just blew my mind. I'm going to play with this. Thanks a
lot, I've really learned a lot in just that small bit. I don't have
much experience in playing with a lot of the 'private' calls such as
__call__. I need to do some more reading.

Roger.
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      12-19-2008
Roger wrote:

>> either. I'd suggest a plain-python workaround along the lines of

>
> Wow. You just blew my mind. I'm going to play with this. Thanks a
> lot, I've really learned a lot in just that small bit. I don't have
> much experience in playing with a lot of the 'private' calls such as
> __call__. I need to do some more reading.


Here's a non-OO variant:

funcs = []
def call(event):
for f in list(funcs): # *
f(event)
root.bind("<1>", call)

funcs.append(test)
funcs.append(test2)
root.bind("<1>", call)

def unbind():
print "unbind"
funcs.remove(test2)

I does the same, but is a bit harder to manage if you have more than one
event/widget to deal with.

(*) iterating over a copy of the list of functions is slightly more robust
as it will not accidentally skip callbacks when the original list is
modified during iteration. I suggest that you change the OO version
accordingly.

Peter
 
Reply With Quote
 
fabien fabien is offline
Junior Member
Join Date: Dec 2011
Posts: 1
 
      12-04-2011
my way to handle tcl nonsense is just to copy it...

Here is a workaround bypassing the bug in Tkinter and calling tk directly.

Code:
#!/usr/bin/env python                                                                                          

import Tkinter

def unbind(widget, sequence, funcid):
  '''unbind funcid callback for sequence on widget                                                             
                                                                                                               
  preserve other binding in case of multiple bindings.                                                         
  '''
  #construct a string containing existing binding minus funcid one                                             
  remain_bindings = "\n".join([e for e in widget.bind(sequence).split("\n") if e and e.find(funcid) == -1 ])
  widget.tk.call('bind', widget, sequence,remain_bindings)

def test(event):
  print 'test'

def test2(event):
  print 'test2'

root = Tkinter.Tk()
funcid1 = root.bind("<1>", test)
funcid2 = root.bind("<1>", test2, add='+')
print funcid1, funcid2

#replace                                                                                                       
#root.unbind("<1>", funcid=funcid2)                                                                            
#by                                                                                                            
unbind(root,"<1>", funcid=funcid2)

root.mainloop()
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Unbinding Tkinter default bindings for Listbox Roger Python 7 01-13-2009 01:13 AM
Unbinding multiple variables Johnny Lin Python 11 01-24-2005 08:27 PM
Unbinding sockets in threads.. Richard Spooner Python 0 08-03-2004 07:47 AM
Re: UNbinding a socket Sin C++ 2 06-25-2003 06:27 PM
Re: (OT) UNbinding a socket Michael Furman C++ 0 06-23-2003 07:41 PM



Advertisments