如何实现Python编写的图形界面可以自由拖动

 更新时间:2024年11月15日 08:51:03   作者:PythonFun  
我们使用python中的tkinter进行编程时,往往需要一种功能就是我们可以随意拖动这个界面,放置在任何位置,下面我们就来看看Python如何实现这一效果吧

一、问题的提出

我们使用python中的tkinter进行编程时,往往需要一种功能就是我们可以随意拖动这个界面,放置在任何位置,而不是只能拖动标题栏,这样使我们的程序用起来更加便捷和丝滑。

二、问题分析

如果要实现这种方法,我们可以定义函数,也可以做一个装饰器,到时相当于给我们的程序添加了一个新的功能一样,这样的逻辑就更好理解了。

三、问题的解决

1. 直接用函数的方法

这种方法是最原始的,我们可以直接把它加入到以函数写法的程序中,通过定义两个函数,包括on_drag_start和on_drag_motion,通过获取鼠标的新位置,来实现界面的位置移动。

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
    root.geometry(f"+{x_new}+{y_new}")
 
    x_start = event.x_root
    y_start = event.y_root
 
root = tk.Tk()
root.geometry("400x300")
 
# 仅将事件处理程序绑定到根窗口的背景上
root.bind('<Button-1>', on_drag_start)
root.bind('<B1-Motion>', on_drag_motion)
 
# 添加一个示例控件
button = tk.Button(root, text="按钮")
button.pack(pady=20)
 
label = tk.Label(root, text="移动窗口")
label.pack(pady=20)
 
root.mainloop()

2. 通过装饰器来实现

虽然函数的方法就可以实现,那么我们可以把这两个函数放在装饰器里面,调用时用@函数名就可以了。在下面的代码中,我们定义了一个draggable_window这个装饰器,可以用于为函数添加新的功能。我们create_window()前面添加了@draggable_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
            root.geometry(f"+{x_new}+{y_new}")
 
            root.x_start = event.x_root
            root.y_start = event.y_root
 
        root.bind('<Button-1>', on_drag_start)
        root.bind('<B1-Motion>', on_drag_motion)
        
        return root
    return wrapper
 
@draggable_window
def create_window():
    root = tk.Tk()
    root.geometry("400x300")
 
    # 添加控件
    button = tk.Button(root, text="按钮")
    button.pack(pady=20)
 
    label = tk.Label(root, text="移动窗口")
    label.pack(pady=20)
 
    return root
 
# 启动窗口
root = create_window()
root.mainloop()

DraggableWindow 类封装了窗口的创建、拖动功能和控件的添加。

on_drag_start 和 on_drag_motion 方法分别处理拖动的起点和拖动过程。

add_widgets 方法用于向窗口添加按钮和标签。

run 方法启动 mainloop(),以显示窗口。

3. 把装饰器写成类去装饰另一个程序添加新功能

我们还可以定义完装饰器后放入一个类中,直接去修饰另一个类,代码如下,注意装饰器的位置。这样的写法逻辑分明,条理清楚,不想使用这个拖动这个功能,直接删除装饰器的类,就可以了。

import tkinter as tk
 
# 定义拖动功能的装饰器
def 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 = self.root.winfo_x() + delta_x
            y_new = self.root.winfo_y() + delta_y
            self.root.geometry(f"+{x_new}+{y_new}")
 
            self.x_start = event.x_root
            self.y_start = event.y_root
 
        # 将拖动事件绑定到窗口
        self.root.bind('<Button-1>', on_drag_start)
        self.root.bind('<B1-Motion>', on_drag_motion)
 
    return wrapper
 
class DraggableWindow:
    @draggable
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry("400x300")
 
        # 添加控件
        self.add_widgets()
 
    def add_widgets(self):
        button = tk.Button(self.root, text="按钮")
        button.pack(pady=20)
 
        label = tk.Label(self.root, text="移动窗口")
        label.pack(pady=20)
 
    def run(self):
        self.root.mainloop()
 
# 启动窗口
app = DraggableWindow()
app.run()

上面代码中,draggable 装饰器应用到类的 __init__ 方法上,这样在类实例化时,窗口会自动绑定拖动事件。

装饰器内部通过 self.root.bind 绑定拖动功能。

这样封装后,拖动功能的逻辑被封装在装饰器中,类的代码保持清晰简洁。

三、学后总结

1. 未来在编程中,常用的功能貌似都可以包装成一个装饰器或者一个可以调用的模块的形式,这样实现主程序和一些功能性的组件分离,修改、调试程序就更加方便。

2. 今天的学习中,从单个的函数实现,到简单的装饰器以及类装饰器的实现,复杂程度进一步提升,应用的逻辑也更多加清晰。

3. 学习Python是一个认识不断加深的过程,像装饰器这样难理解的概念,如果单纯从文字上理解比较困难,可以放在小项目中,逐步消化,增进理解。

到此这篇关于如何实现Python编写的图形界面可以自由拖动的文章就介绍到这了,更多相关Python图形界面自由拖动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python3从零开始搭建一个语音对话机器人的实现

    Python3从零开始搭建一个语音对话机器人的实现

    这篇文章主要介绍了Python3从零开始搭建一个语音对话机器人的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Python登录QQ邮箱发送邮件的实现示例

    Python登录QQ邮箱发送邮件的实现示例

    本文主要介绍了Python登录QQ邮箱发送邮件的实现示例,主要就是三步,登录邮件、写邮件内容、发送,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧<BR>
    2023-08-08
  • Python+Socket实现基于TCP协议的客户与服务端中文自动回复聊天功能示例

    Python+Socket实现基于TCP协议的客户与服务端中文自动回复聊天功能示例

    这篇文章主要介绍了Python+Socket实现基于TCP协议的客户与服务端中文自动回复聊天功能,结合实例形式分析了Python+Socket实现带自动回复功能的TCP聊天程序相关操作方法与注意事项,需要的朋友可以参考下
    2017-08-08
  • 详细一文带你分清Python中的模块、包和库

    详细一文带你分清Python中的模块、包和库

    这篇文章主要介绍了详细一文带你分清Python中的模块、包和库,Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句,模块能定义函数,类和变量,模块也能包含可执行的代码,需要的朋友可以参考下
    2023-08-08
  • 浅谈python图片处理Image和skimage的区别

    浅谈python图片处理Image和skimage的区别

    这篇文章主要介绍了浅谈python图片处理Image和skimage的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Python实现的NN神经网络算法完整示例

    Python实现的NN神经网络算法完整示例

    这篇文章主要介绍了Python实现的NN神经网络算法,结合完整实例形式分析了Python使用numpy、matplotlib及sklearn模块实现NN神经网络相关算法实现技巧与操作注意事项,需要的朋友可以参考下
    2018-06-06
  • python线程启动的四种方式总结

    python线程启动的四种方式总结

    这篇文章主要给大家介绍了关于python线程启动的四种方式,线程可以完成一定任务,可以和其它线程共享父进程的共享变量和部分环境,相互协作来完成任务,需要的朋友可以参考下
    2024-01-01
  • django站点管理详解

    django站点管理详解

    这篇文章主要介绍了django站点管理详解,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • 深人了解Python上下文管理器

    深人了解Python上下文管理器

    这篇文章主要为大家介绍了Python上下文管理器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>
    2021-12-12
  • Python中基础数据类型 set集合知识点总结

    Python中基础数据类型 set集合知识点总结

    在本篇文章里小编给大家总结了一篇关于Python中基础数据类型 set集合知识点总结内容,有需要的朋友们可以学习下。
    2021-08-08

最新评论