使用 tkinterdnd2 的 CustomTkinter 小部件和拖放的奇怪行为

问题描述 投票:0回答:1

我开始使用 Tkinter 查看拖放,并根据答案,我在此处生成了上一个问题的更新 2。我还参考了这个答案

基于这些,我制作了这段显然未完成的代码:

import tkinter as tk
import customtkinter as ctk
import tkinter
from tkinterdnd2 import TkinterDnD, DND_ALL


class CTk(ctk.CTk, TkinterDnD.DnDWrapper):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.TkdndVersion = TkinterDnD._require(self)


class DnD():
    """Drag and Drop management class, used to drag one widget over another, target widget.
    The target widget then takes on the colours of the dragged
    widget."""
    payload = ['', '']

    def __init__(self, widget, enable_drag=True, enable_drop=True):
        self.widget = widget
        root.update_idletasks()

        self.widget_x_restore = widget.winfo_x()
        self.widget_y_restore = widget.winfo_y()

        if enable_drag:
            self.widget.drag_source_register(1)
            self.widget.bind("<Button-1>", self.drag_start)
            self.widget.bind("<B1-Motion>", self.drag_motion)
            self.widget.bind("<ButtonRelease-1>", self.restore_position)
            DnD.payload = [self.widget.cget('fg_color'), self.widget.   cget('hover_color')]

        if enable_drop:
            self.widget.bind("<<Drop>>", self.drop)

    def drag_start(self, event):
        """The drag_start method is a callback function bound to a mouse action (Button-1 click)."""
        widget = event.widget
        widget.startX = event.x
        widget.startY = event.y
        print(f'Dragging...')
        # widget.lift()

    def drag_motion(self, event):
        """Callback method, used in binding to mouse pointer motion, causing the dragged widget motion."""
        widget = event.widget

        x = widget.winfo_x() - event.x
        y = widget.winfo_y() - event.y
        widget.place(x=x, y=y)

    def drop(self, event):
        """Register a widget as a drop target."""
        target_button = event.widget  # Access the target button
        if isinstance(target_button, ctk.CTkButton):
            fg_colour, hover_colour = DnD.payload
            target_button.configure(fg_color=fg_colour, hover_colour=hover_colour)  # Change target button color

    def restore_position(self, event):

        self.widget.place(x=self.widget_x_restore, y=self.widget_y_restore)
        root.update_idletasks()  # move top widget (source widget), to access widget below (target widget)

        x, y = event.widget.winfo_pointerxy()
        target = event.widget.winfo_containing(x, y)

        target.event_generate("<<Drop>>")


class App(CTk):
    def __init__(self):
        super().__init__()
        pass


if __name__ == "__main__":
    root = App()
    root.geometry("600x400+200+100")
    button1 = ctk.CTkButton(root,
                            text="button1",
                            fg_color="red",
                            hover_color="red",
                            width=100,
                            height=50)
    button1.place(x=10, y=100)

    button2 = ctk.CTkButton(root,
                            text="button2",
                            fg_color="blue",
                            hover_color="blue",
                            width=100,
                            height=50)
    button2.place(x=200, y=200)

    # Register the buttons for drag and drop.
    button1_dnd = DnD(button1)
    button2_dnd = DnD(button2)

    root.mainloop()

问题是,当我点击并尝试拖动按钮时,按钮不是移动,而是缩小或消失。

有人经历过并解决过这个问题吗?

谢谢。

python tkinter drag-and-drop customtkinter
1个回答
0
投票

经过一番摸索和重构后,我想出了一个不利用 tkinterdnd2 的解决方案,但可以使用 CustomTkinter 按钮,这是我的主要要求:

import customtkinter as ctk

class CTkButtonDnD():
    """Facilitate drag and drop of CustomTkinter CTkButton.
    Drag a CTkButton over another CTkButton and update the drop target colours,to
    those of the dragged widget. When the operation is completed, the dragged
    widget is returned to its original position."""
    source_fg_color = ''
    source_hover_color = ''

    def __init__(self, widget, enable_drag=True, enable_drop=True):
        self.widget = widget
        self.enable_drag = enable_drag
        self.enable_drop = enable_drop

        print(f'Type of widget: {self.widget}')

        self.initial_position = None
        if enable_drag:
            widget.bind("<Button-1>", self.on_click)
            widget.bind("<ButtonRelease-1>", lambda event: self.restore_position(widget))
        # self.widget_x_restore, self.widget_y_restore = 0, 0
            root.update_idletasks()
            self.widget_x_restore = widget.winfo_x()
            self.widget_y_restore = widget.winfo_y()
            self.pointer_start_x, self.pointer_start_y = 0, 0

        if enable_drop:
            self.widget.bind("<<Drop>>", self.drop)

        self.widget.bind("<Destroy>", self.cleanup)

    def cleanup(self, event=None):
        """Cleanup method to be called when the associated CTkButton widget is destroyed."""
        self.widget.unbind_all()

    def on_click(self, event):
        self.pointer_start_x, self.pointer_start_y = event.x, event.y
        widget = event.widget.master
        print(f'Type of clicked widget: {event.widget}')
        print(f'Type of clicked widget parent: {event.widget.master}')
        if self.enable_drag:
            CTkButtonDnD.source_fg_color = widget.cget('fg_color')
            CTkButtonDnD.source_hover_color = widget.cget('hover_color')
            self.widget.bind("<B1-Motion>", self.drag_motion)

        if self.enable_drop:
            self.widget.bind("<ButtonRelease-1>", self.drop)

    def drag_motion(self, event):
        x = self.widget.winfo_x() + event.x - self.pointer_start_x
        y = self.widget.winfo_y() + event.y - self.pointer_start_y
        self.widget.lift()
        self.widget.place(x=x, y=y)

    def drop(self, event):
        self.widget.lower()
        widget = event.widget
        widget.master.configure(fg_color=CTkButtonDnD.source_fg_color, hover_color=CTkButtonDnD.source_hover_color)
    def restore_position(self, widget):
        widget.lower()
        x, y = root.winfo_pointerxy()
        target_widget = root.winfo_containing(x, y)
        widget.place(x=self.widget_x_restore, y=self.widget_y_restore)
        root.update_idletasks()
        target_widget.event_generate('<<Drop>>')

def reset_colors():
    button1.configure(fg_color="red", hover_color="green")
    button2.configure(fg_color="blue", hover_color="black")

root = ctk.CTk()

root.geometry("310x200+200+200")

button1 = ctk.CTkButton(root, fg_color="red", hover_color="green", width=100, height=50)
button1.place(x=10, y=50)
button1_dnd = CTkButtonDnD(button1)

button2 = ctk.CTkButton(root, fg_color="blue", hover_color="black", width=100, height=50)
button2.place(x=200, y=50)
button2_dnd = CTkButtonDnD(button2, True, True)

button_reset = ctk.CTkButton(root, text='Reset', width=100, command=reset_colors)
button_reset.place(x=200, y=160)

root.mainloop()
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.