SoFunction
Updated on 2025-04-14

How to implement the graphical interface written in Python that can be dragged freely

1. Problem raising

When we use tkinter in python for programming, we often need a function that we can drag the interface at will and place it anywhere instead of just dragging the title bar, which makes our program more convenient and silky.

2. Problem analysis

If we want to implement this method, we can define functions or make a decorator. At that time, it is equivalent to adding a new function to our program, and this logic will be better understood.

3. Solve the problem

1. Directly use the function method

This method is the most primitive. We can directly add it to a program written in a function. By defining two functions, including on_drag_start and on_drag_motion, we can achieve the position movement of the interface by obtaining the new position of the mouse.

import tkinter as tk
 
def on_drag_start(event):
    global x_start, y_start
    x_start = event.x_root
    y_start = event.y_root
 
def on_drag_motion(event):
    global x_start, y_start
    delta_x = event.x_root - x_start
    delta_y = event.y_root - y_start
    x_new = root.winfo_x() + delta_x
    y_new = root.winfo_y() + delta_y
    (f"+{x_new}+{y_new}")
 
    x_start = event.x_root
    y_start = event.y_root
 
root = ()
("400x300")
 
# Only bind event handlers to the background of the root window('<Button-1>', on_drag_start)
('<B1-Motion>', on_drag_motion)
 
# Add a sample controlbutton = (root, text="Button")
(pady=20)
 
label = (root, text="Mobile Window")
(pady=20)
 
()

2. Implement through a decorator

Although the function method can be implemented, we can put these two functions in the decorator and use the @ function name when calling. In the following code, we define a draggable_window decorator that can be used to add new functions to functions. We have added @draggable_window in front of create_window(), so that we can add new features to the new window.

import tkinter as tk
 
def draggable_window(func):
    def wrapper(*args, **kwargs):
        root = func(*args, **kwargs)
        
        def on_drag_start(event):
            root.x_start = event.x_root
            root.y_start = event.y_root
 
        def on_drag_motion(event):
            delta_x = event.x_root - root.x_start
            delta_y = event.y_root - root.y_start
            x_new = root.winfo_x() + delta_x
            y_new = root.winfo_y() + delta_y
            (f"+{x_new}+{y_new}")
 
            root.x_start = event.x_root
            root.y_start = event.y_root
 
        ('<Button-1>', on_drag_start)
        ('<B1-Motion>', on_drag_motion)
        
        return root
    return wrapper
 
@draggable_window
def create_window():
    root = ()
    ("400x300")
 
    # Add control    button = (root, text="Button")
    (pady=20)
 
    label = (root, text="Mobile Window")
    (pady=20)
 
    return root
 
# Start the windowroot = create_window()
()

The DraggableWindow class encapsulates window creation, dragging functionality and control addition.

The on_drag_start and on_drag_motion methods handle the starting point of the drag and the drag process respectively.

The add_widgets method is used to add buttons and labels to the window.

The run method starts mainloop() to display the window.

3. Write the decorator into a class to decorate another program and add new functions

We can also define the decorator and put it in one class and directly modify the other class. The code is as follows, pay attention to the location of the decorator. This writing method is clear and organized. If you don’t want to use this drag function, just delete the decorator class directly.

import tkinter as tk
 
# Decorators that define drag functiondef draggable(func):
    def wrapper(self, *args, **kwargs):
        func(self, *args, **kwargs)
        
        def on_drag_start(event):
            self.x_start = event.x_root
            self.y_start = event.y_root
 
        def on_drag_motion(event):
            delta_x = event.x_root - self.x_start
            delta_y = event.y_root - self.y_start
            x_new = .winfo_x() + delta_x
            y_new = .winfo_y() + delta_y
            (f"+{x_new}+{y_new}")
 
            self.x_start = event.x_root
            self.y_start = event.y_root
 
        # Bind drag event to window        ('<Button-1>', on_drag_start)
        ('<B1-Motion>', on_drag_motion)
 
    return wrapper
 
class DraggableWindow:
    @draggable
    def __init__(self):
         = ()
        ("400x300")
 
        # Add control        self.add_widgets()
 
    def add_widgets(self):
        button = (, text="Button")
        (pady=20)
 
        label = (, text="Mobile Window")
        (pady=20)
 
    def run(self):
        ()
 
# Start the windowapp = DraggableWindow()
()

In the above code, the draggable decorator is applied to the class's __init__ method, so that when the class is instantiated, the window will automatically bind the drag event.

The decorator is internally bound and dragged.

After encapsulation in this way, the logic of the drag function is encapsulated in the decorator, and the code of the class remains clear and concise.

3. After-study summary

1. In the future, in programming, commonly used functions may seem to be packaged into a decorator or a module that can be called, so as to separate the main program from some functional components, making it more convenient to modify and debug the program.

2. In today's learning, from the implementation of single function to the implementation of simple decorators and class decorators, the complexity has been further improved, and the logic of the application has become clearer.

3. Learning Python is a process of deepening understanding. If concepts like decorators are difficult to understand simply from a text, they can be placed in small projects and gradually digested to enhance understanding.

This is the article about how to implement the free drag of the graphical interface written in Python. For more related content related to free drag of the Python graphical interface, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!