You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to create a drag-and-drop GUI interface featuring several CTkListboxes, however, I can't get the drag-drop functionality to work. I've bound the items to <ButtonPress-1> but the items never register as being clicked. I get no output from "on_click" print statements unless the click is out of bounds and the response is "Nearest index: None"
This works perfectly with a regular tk listbox (and the code is much neater due to the presence of .nearest()), but I'm not sure why the CTkListbox doesn't work.
Note that on_drop is probably broken, haven't gotten to the point of being able to debug it yet.
import customtkinter as ctk
from CTkListbox import *
class DragDropGUI(ctk.CTk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Create the list of objects
objects = ["Object 1", "Object 2", "Object 3", "Object 4"]
ctk.set_appearance_mode('light')
# Create the listbox for objects
self.object_listbox = CTkListbox(self, width=200, height=400)
for obj in objects:
self.object_listbox.insert(ctk.END, obj)
self.object_listbox.pack(side=ctk.LEFT, padx=10, pady=10)
# Create the bin listboxes
self.bin1_listbox = CTkListbox(self, width=200, height=400)
self.bin1_listbox.pack(side=ctk.LEFT, padx=10, pady=10)
self.bin2_listbox = CTkListbox(self, width=200, height=400)
self.bin2_listbox.pack(side=ctk.LEFT, padx=10, pady=10)
self.bin3_listbox = CTkListbox(self, width=200, height=400)
self.bin3_listbox.pack(side=ctk.LEFT, padx=10, pady=10)
self.bin4_listbox = CTkListbox(self, width=200, height=400)
self.bin4_listbox.pack(side=ctk.LEFT, padx=10, pady=10)
# Enable drag and drop functionality
self.object_listbox.bind("<ButtonPress-1>", self.on_start_drag)
self.bin1_listbox.bind("<ButtonPress-1>", self.on_start_drag)
self.bin2_listbox.bind("<ButtonPress-1>", self.on_start_drag)
self.bin3_listbox.bind("<ButtonPress-1>", self.on_start_drag)
self.bin4_listbox.bind("<ButtonPress-1>", self.on_start_drag)
self.object_listbox.bind("<B1-Motion>", self.on_drag_motion)
self.bin1_listbox.bind("<B1-Motion>", self.on_drag_motion)
self.bin2_listbox.bind("<B1-Motion>", self.on_drag_motion)
self.bin3_listbox.bind("<B1-Motion>", self.on_drag_motion)
self.bin4_listbox.bind("<B1-Motion>", self.on_drag_motion)
self.object_listbox.bind("<ButtonRelease-1>", self.on_drop)
self.bin1_listbox.bind("<ButtonRelease-1>", self.on_drop)
self.bin2_listbox.bind("<ButtonRelease-1>", self.on_drop)
self.bin3_listbox.bind("<ButtonRelease-1>", self.on_drop)
self.bin4_listbox.bind("<ButtonRelease-1>", self.on_drop)
def on_start_drag(self, event):
# Get the selected item and its index
widget = event.widget
y = event.y
nearest_index = None
min_distance = float("inf")
asdf, height = widget.size()
for i in range(height):
item_y, item_height = widget.bbox(i)[1:3]
item_center_y = item_y + item_height / 2
distance = abs(y - item_center_y)
if distance < min_distance:
min_distance = distance
nearest_index = i
print("Nearest index:", nearest_index)
if nearest_index is not None:
try:
self.drag_data = {"widget": widget, "index": nearest_index, "text": widget.get(nearest_index)}
print("Drag data:", self.drag_data)
print('item grabbed')
except AttributeError: # clicks between objects
self.drag_data = None
else:
self.drag_data = None
def on_drag_motion(self, event):
# Change the cursor to a hand symbol
event.widget.config(cursor="hand2")
def on_drop(self, event):
# Get the widget we dropped on
target_widget = self.winfo_containing(event.x_root, event.y_root)
# Check if the target widget is a listbox and the y-coordinate is within the target widget
if isinstance(target_widget, CTkListbox) and 0 <= event.y < target_widget.winfo_height():
# Get the position where the item was dropped
# Calculate the drop index manually
drop_index = None
asdf, height = target_widget.size()
y = event.y - target_widget.winfo_rooty() - target_widget.winfo_y()
for i in range(height):
item_y = target_widget.bbox(i)[1]
if y < item_y:
drop_index = i
break
if drop_index is None:
drop_index = target_widget.size()
print("Drop index:", drop_index)
# Add the dragged item to the target listbox
target_widget.insert(drop_index, self.drag_data["text"])
print('item dropped')
# Remove the item from the original listbox
self.drag_data["widget"].delete(self.drag_data["index"])
# force the target listbox to update
target_widget.activate(drop_index)
# Reset the drag_data
self.drag_data = {"widget": None, "index": None, "text": None}
if __name__ == "__main__":
app = DragDropGUI()
app.mainloop()
The text was updated successfully, but these errors were encountered:
@ohshitgorillas Drag and drop is not implemented in this ctk listbox, but it can be achieved if you modify the list button by binding different events.
I will try to add this feature in next version.
I'm trying to create a drag-and-drop GUI interface featuring several CTkListboxes, however, I can't get the drag-drop functionality to work. I've bound the items to
<ButtonPress-1>
but the items never register as being clicked. I get no output from "on_click" print statements unless the click is out of bounds and the response is "Nearest index: None"This works perfectly with a regular tk listbox (and the code is much neater due to the presence of
.nearest()
), but I'm not sure why the CTkListbox doesn't work.Note that on_drop is probably broken, haven't gotten to the point of being able to debug it yet.
The text was updated successfully, but these errors were encountered: