tkinter调用overrideredirect(1)后拖拽窗口时内部控件消失该如何解决?
问题根因
- 冗余事件绑定:原代码每次触发
<B1-Motion>事件时都重新绑定一次事件回调,快速拖拽会产生大量冗余回调阻塞事件队列,导致tkinter无法及时重绘窗口内控件,出现控件消失的情况。 - 第三方坐标库不同步:使用第三方
mouse库获取全局坐标,和tkinter本身的事件循环不同步,快速移动或拖拽到屏幕边缘时容易出现坐标计算溢出,窗口可能被定位到不可见区域或是触发重绘异常。 - 容器选择不合理:用
Label控件作为Entry的父容器,Label本身是展示类控件,对子控件的重绘优化远低于专门的容器类控件Frame,快速移动场景下子控件重绘优先级被挤压,就会出现空白。
修正后的可运行代码
from tkinter import * root = Tk() root.overrideredirect(1) root.geometry("700x200+500+200") # 改用Frame作为父容器,重绘优先级更高 BG = Frame(root, bd=0) BG.pack(fill=BOTH, expand=True) # 记录鼠标按下时的偏移量 offset_x = 0 offset_y = 0 def on_press(e): global offset_x, offset_y # 记录鼠标相对于窗口的偏移量 offset_x = e.x offset_y = e.y def on_drag(e): # 直接用tkinter自带的全局坐标计算,和事件循环完全同步 root.geometry(f'+{e.x_root - offset_x}+{e.y_root - offset_y}') var1 = StringVar() entry1 = Entry(BG, width=80, textvariable=var1) entry1.place(x=170,y=57) var2 = StringVar() entry2 = Entry(BG,width=80, textvariable=var2) entry2.place(x=170,y=100) # 只绑定一次事件,不需要反复绑定 BG.bind('<Button-1>', on_press) BG.bind('<B1-Motion>', on_drag) root.mainloop()
改动说明
- 移除了冗余的事件绑定逻辑,只在初始化时绑定一次按下和拖拽事件,避免事件队列阻塞
- 删掉了第三方
mouse库依赖,全部使用tkinter事件对象自带的坐标属性计算窗口位置,坐标计算完全和事件循环同步,不会出现偏差 - 将父容器从
Label替换为专门的容器控件Frame,优化内部子控件的重绘逻辑,快速移动也不会出现控件丢失的情况
内容的提问来源于stack exchange,提问作者user13112566
相关产品推荐
相关产品推荐

