SOLVED: Tkinter button-motion event behaves differently underWindows and Linux
From
John O'Hagan@research@johnohagan.com to
comp.lang.python on Mon Nov 11 21:46:16 2024
From Newsgroup: comp.lang.python
I'm posting this in case anyone else encounters the same problem, and
to ask for suggestions, if any, about a better way to do it.
I'm implementing a method for dragging embedded widgets on a Text
widget. When the left mouse button is held down over an embedded widget
and the mouse is dragged across other widgets embedded in the same
parent, the original widget moves to the new positions until the button
is released.
Here's some minimal code:
-------
from tkinter import *
text = Text(Tk())
text.pack()
def drag(e):
print(e.widget)
target = e.widget.winfo_containing(e.x_root, e.y_root)
if target and target not in (text, e.widget):
if text.compare(target, '>', e.widget):
target = f'{target} + 1 char'
text.window_create(target, window=e.widget)
for n in ('1', '2', '3'):
l=Label(text, text=n, width=10)
#l.bind('<Button-1>', lambda e:e.widget.grab_set())
l.bind('<B1-Motion>', drag)
#l.bind('<ButtonRelease-1>', lambda e:e.widget.grab_release())
text.window_create(END, window=l)
mainloop()
-------
This works as intended for me on Windows (11). The print statement
always shows the name of the first selected widget while the button is
held down, regardless of where the mouse is dragged to.
But on Linux (Debian testing with Gnome), for me the above code only
moves the widget to the first new position it is dragged to, any
further dragging is ineffective, and the print statement shows the
names of the subsequently-traversed widgets.
There is a further issue in the real code (not shown here) also on
Linux only, where if the cursor traverses any other widgets bound to '<B1-Motion>', they are also triggered, which is not intended.
Just a guess, but it seems that on Linux, the focus switches to
whatever widget is under the cursor even during dragging, so any
bindings on the originally-clicked widget are no longer triggered,
whereas Windows maintains focus on the originally-clicked widget during dragging until the button is released.
If that's the case (and I never thought I'd say this), I think Windows
is right! But for all I know it might be the window manager or
something else.
I eventually figured out that the commented lines calling grab_set and grab_release solved the issue for me on Linux.
I haven't found this documented anywhere and I'm interested to know if
anyone can cast any light on it.
Thanks
--- Synchronet 3.20a-Linux NewsLink 1.114