On 2023-09-12 06:43, John O'Hagan via Python-list wrote:
On Mon, 2023-09-11 at 22:25 +0200, Mirko via Python-list wrote:
Am 11.09.23 um 14:30 schrieb John O'Hagan via Python-list:
> I was surprised that the code below prints 'called' three times.
> > > from tkinter import *
> from tkinter.ttk import *
> > root=Tk() > > def callback(*e):
>      print('called')
> > tree = Treeview(root)
> tree.pack()
> > iid = tree.insert('', 0, text='test') > > tree.selection_set(iid)
> tree.selection_remove(iid)
> tree.selection_set(iid)
> > tree.bind('<<TreeviewSelect>>', callback) > > mainloop() > > In other words, selection events that occurred _before_ the
> callback
> function was bound to the Treeview selections are triggering the
> function upon binding. AFAIK, no other tk widget/binding
> combination
> behaves this way (although I haven't tried all of them).
> > This was a problem because I wanted to reset the contents of the
> Treeview without triggering a relatively expensive bound function,
> but
> found that temporarily unbinding didn't prevent the calls.
> > I've worked around this by using a regular button-click binding for
> selection instead, but I'm curious if anyone can cast any light on
> this.
> > Cheers > > John


AFAIK (it's been quite some time, since I used Tk/Tkinter):

These selection events are not triggered upon binding, but after the mainloop has startet. Tk's eventloop is queue-driven, so the tree.selection_{set,remove}() calls just place the events on the queue. After that, you setup a callback and when the mainloop starts, it processes the events from the queue, executing the registered callback.

I seem to remember, that I solved a similar issue by deferring the callback installation using root.after().


from tkinter import *
from tkinter.ttk import *

root=Tk()

def callback(*e):
     print('called')

tree = Treeview(root)
tree.pack()

iid = tree.insert('', 0, text='test')

tree.selection_set(iid)
tree.selection_remove(iid)
tree.selection_set(iid)

root.after(100, lambda: tree.bind('<<TreeviewSelect>>', callback))

mainloop()



This does not print "called" at all after startup (but still selects the entry), because the callback has not been installed when the mainloop starts. But any subsequent interaction with the list (clicking) will print it (since the callback is then setup).

HTH


Thanks for your reply. However, please see the example below, which is
more like my actual use-case. The selection events take place when a
button is pressed, after the mainloop has started but before the
binding. This also prints 'called' three times.

from tkinter import *
from tkinter.ttk import *

class Test:

    def __init__(self):
       root=Tk()
       self.tree = Treeview(root)
       self.tree.pack()
       self.iid = self.tree.insert('', 0, text='test')
       Button(root, command=self.temp_unbind).pack()
       mainloop()

    def callback(self, *e):
       print('called')
def temp_unbind(self):
       self.tree.unbind('<<TreeviewSelect>>')
       self.tree.selection_set(self.iid)
       self.tree.selection_remove(self.iid)
       self.tree.selection_set(self.iid)
       self.tree.bind('<<TreeviewSelect>>', self.callback)
       #self.tree.after(0, lambda: self.tree.bind('<<TreeviewSelect>>',
       self.callback))
c=Test()

It seems the events are still queued, and then processed by a later
bind?

However, your solution still works, i.e. replacing the bind call with
the commented line. This works even with a delay of 0, as suggested in
Rob Cliffe's reply. Does the call to after clear the event queue
somehow?

My issue is solved, but I'm still curious about what is happening here.

Yes, it's still queuing the events.
When an event occurs, it's queued.

So, you unbound and then re-bound the callback in temp_unbind?

Doesn't matter.

All that matters is that on returning from temp_unbind to the main event loop, there are events queued and there's a callback registered, so the callback is invoked.

Using the .after trick queues an event that will re-bind the callback _after_ the previous events have been handled.
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to