I am writing a drag and drop app where I drag data from a tree view to an entry widget. I want to be able to use the item from the tree that is under the cursor when the mouse button is pressed.
I can see how to obtain the selected item, but that is not returned at the moment of the event
Is there any way to return the item?
import tkinter as tk
from tkinter import ttk
def main() -> None:
root = tk.Tk()
root.title('Tree coords')
tree = ttk.Treeview(root, height=30, show='headings',)
tree.grid(row=0, column=0, sticky=tk.NSEW)
tree.bind("<ButtonPress-1>", on_start)
col_list = ('Names', 'Names', 30)
tree['columns'] = col_list
for name in ['ab', 'ef', 'mn']:
values = (name)
tree.insert('', 'end', values=values)
root.mainloop()
def on_start(event=None):
widget = event.widget
selected_items = widget.selection()
x, y = event.widget.winfo_pointerxy()
print(x, y, selected_items)
if __name__ == '__main__':
main()
The problem is that your binding is called before the treeview
is updated. The treeview
class bindings happen after the widget-specific bindings, so the selection()
function will return the previously selected item. One way to fix this is to create the binding after the class bindings (see here for more information).
You can also make the binding to "<<TreeviewSelect>>"
instead of "<ButtonPress-1>"
, but it can be triggered not only by the mouse button (for example, by the "Up" or "Down" keys)).
A third way is to use a function that can work almost independently of the treeview
class binding. For example, you can use the identify_row
method to get the item at some Y position. In your case, just replace selected_items = widget.selection()
with selected_items = widget.identify_row(event.y)
. Although this is not an exact replacement, since the identify_row()
method always returns only one element, while the selection()
method can return multiple elements.