'Activate other widgets while mouse dragging
I have multiple Tkinter.labels in a row and i would like the user to be able to click and drag their mouse over each one, activating them in the process.
I know about bindings, but i need multiple events in a single binding. Ive been messing around with <Button-1> and <Enter>, however i need a callback to be called only when both are true.
I know l.bind('<Button-1>,<Enter>', ...) is not valid.
Anyone with more Tkinter experience know of a way to chain binding, or make a multi-bind??
Solution 1:[1]
I encountered this same problem today and thanks to @Bryan Oakley's answer I was able to code a working solution. I will share my code in the hope that it will help someone someday.
This example builds 2 tkinter TreeViews, and enables dragging-and-dropping treeItems between the 2 trees. The key point is that by binding both trees to the B1-motion event, both trees are able to respond to the events.
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class TreeItem:
"""
Keeps a reference to a treeItem together with its parent tree.
"""
def __init__(self, tree, item):
self.tree = tree
self.item = item
self.itemTxt = tree.item(item,"text")
def __str__(self):
"""
Prints 'treename, itemname' upon calling str(TreeItem)
"""
return f'{self.tree}, {self.itemTxt}'
class Mouse(metaclass=Singleton):
"""
Handles treeitem clicking, dragging, dropping and shows feedback messages about them.
"""
def __init__(self, root):
self.root = root
self.clicked_item = None
self.is_dragging = False
self.drag_time = 0
self.current_hovering_widget = None
def OnMouseDown(self, event):
clicked_item = self.get_item_under_mouse(event)
print("You clicked on", str(clicked_item))
self.clicked_item = clicked_item
def OnDrag(self, event):
self.is_dragging = True
self.show_drag_init_msg()
self.show_hovering_item_change_msg(event)
self.drag_time += 1
def OnMouseUp(self, event):
if self.is_dragging:
self.finish_drag()
self.show_drop_msg()
self.clicked_item = None
def finish_drag(self):
self.is_dragging = False
self.drag_time = 0
def show_drag_init_msg(self):
if self.drag_time == 0:
print("You are now dragging item", self.clicked_item.tree, self.clicked_item.itemTxt)
def show_hovering_item_change_msg(self, event):
currently_hovering = self.get_item_under_mouse(event)
if str(self.current_hovering_widget) != str(currently_hovering):
print("Mouse is above", str(currently_hovering))
self.current_hovering_widget = currently_hovering
def show_drop_msg(self):
dragged_item:TreeItem = self.clicked_item
dragged_onto:TreeItem = self.current_hovering_widget
print(f'You dropped {str(dragged_item)} onto {str(dragged_onto)}')
def get_item_under_mouse(self, event):
current_tree = self.root.winfo_containing(event.x_root, event.y_root)
current_tree_item = current_tree.identify("item", event.x, event.y)
return TreeItem(tree=current_tree, item=current_tree_item)
class Tree:
def __init__(self, root, row, col):
self.root: tk.Tk = root
self.create_tree(root, row, col)
def OnDrag(self,event):
Mouse(self.root).OnDrag(event)
def OnMouseDown(self, event):
Mouse(self.root).OnMouseDown(event)
def OnMouseUp(self, event):
Mouse(self.root).OnMouseUp(event)
def create_tree(self, root, row, col):
self.tree = ttk.Treeview(root)
self.tree.heading('#0', text='Departments', anchor='w')
self.tree.grid(row=row, column=col, sticky='nsew')
self.add_dummy_data()
# add bindings
self.tree.bind("<ButtonPress-1>", self.OnMouseDown)
self.tree.bind("<ButtonRelease-1>", self.OnMouseUp)
self.tree.bind("<B1-Motion>", self.OnDrag)
def add_dummy_data(self):
# adding data
self.tree.insert('', tk.END, text='Administration', iid=0, open=False)
self.tree.insert('', tk.END, text='Logistics', iid=1, open=False)
self.tree.insert('', tk.END, text='Sales', iid=2, open=False)
self.tree.insert('', tk.END, text='Finance', iid=3, open=False)
self.tree.insert('', tk.END, text='IT', iid=4, open=False)
# adding children of first node
self.tree.insert('', tk.END, text='John Doe', iid=5, open=False)
self.tree.insert('', tk.END, text='Jane Doe', iid=6, open=False)
self.tree.move(5, 0, 0)
self.tree.move(6, 0, 1)
root = tk.Tk()
root.geometry('620x200')
# make two trees
tree1 = Tree(root,0,0)
tree2 = Tree(root,0,1)
# run the app
root.mainloop()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | jnz |
