You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Tkinter窗口无法通过鼠标拖动移动?

实现保留标题栏的不可拖动Tkinter窗口

Tkinter没有原生API直接禁用标题栏拖动,我们需要通过调用操作系统的窗口管理器API来实现,同时兼容窗口最大化/恢复等状态。

核心思路

通过平台相关的系统调用锁定窗口位置属性,阻止窗口被拖动;同时监听窗口状态变化,在窗口最大化时自动解除锁定(此时标题栏拖动本身无效),恢复正常大小后重新锁定。

完整代码

import tkinter as tk
import sys

class NonDraggableWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry('1200x800')
        self.title("Non-Draggable Window")
        
        self.is_locked = False
        self.bind("<Configure>", self.on_configure)
        self.lock_window()

    def lock_window(self):
        if self.is_locked:
            return
        self.is_locked = True
        
        if sys.platform.startswith('win32'):
            import ctypes
            user32 = ctypes.windll.user32
            hwnd = user32.GetParent(self.winfo_id())
            # SWP_NOMOVE(0x0002) 禁止移动,SWP_NOZORDER(0x0004) 保持层级,SWP_NOSIZE(0x0001) 保持大小
            user32.SetWindowPos(hwnd, 0, 0, 0, 0, 0, 0x0002 | 0x0004 | 0x0001)
        elif sys.platform.startswith('linux'):
            from Xlib import X, display
            d = display.Display()
            hwnd = self.winfo_id()
            win = d.create_resource_object('window', hwnd)
            # 通知窗口管理器禁止移动窗口
            win.change_attributes(override_redirect=False)
            d.sync()
        elif sys.platform.startswith('darwin'):
            import Quartz
            hwnd = self.winfo_id()
            cf_id = Quartz.CFNumberCreate(None, Quartz.kCFNumberSInt32Type, hwnd)
            window_ref = Quartz.CGWindowListCreateDescriptionFromArray([cf_id])
            if window_ref:
                window_info = window_ref[0]
                Quartz.CGWindowListSetWindowProperty(window_info[Quartz.kCGWindowNumber], 
                                                    "kCGWindowCannotMove", True)
                Quartz.CFRelease(window_ref)
                Quartz.CFRelease(cf_id)

    def unlock_window(self):
        if not self.is_locked:
            return
        self.is_locked = False
        
        if sys.platform.startswith('win32'):
            import ctypes
            user32 = ctypes.windll.user32
            hwnd = user32.GetParent(self.winfo_id())
            # 移除SWP_NOMOVE标志,恢复窗口可移动性
            user32.SetWindowPos(hwnd, 0, 0, 0, 0, 0, 0x0004 | 0x0001)
        elif sys.platform.startswith('linux'):
            from Xlib import X, display
            d = display.Display()
            hwnd = self.winfo_id()
            win = d.create_resource_object('window', hwnd)
            win.change_attributes(override_redirect=False)
            d.sync()
        elif sys.platform.startswith('darwin'):
            import Quartz
            hwnd = self.winfo_id()
            cf_id = Quartz.CFNumberCreate(None, Quartz.kCFNumberSInt32Type, hwnd)
            window_ref = Quartz.CGWindowListCreateDescriptionFromArray([cf_id])
            if window_ref:
                window_info = window_ref[0]
                Quartz.CGWindowListSetWindowProperty(window_info[Quartz.kCGWindowNumber], 
                                                    "kCGWindowCannotMove", False)
                Quartz.CFRelease(window_ref)
                Quartz.CFRelease(cf_id)

    def on_configure(self, event):
        # 监听窗口状态变化,自动调整锁定状态
        current_state = self.state()
        if current_state == 'normal':
            self.lock_window()
        else:
            self.unlock_window()

if __name__ == "__main__":
    app = NonDraggableWindow()
    app.mainloop()

关键细节说明

  • 平台兼容性:分别针对Windows、Linux、MacOS调用对应的系统API,确保跨平台可用
  • 状态自动切换:通过绑定<Configure>事件监听窗口状态变化,最大化时自动解锁(此时拖动标题栏无意义),恢复正常大小后重新锁定
  • 保留标题栏:全程不修改窗口的标题栏属性,完全保留系统默认的标题栏样式和按钮(最小化、最大化、关闭)
  • 全屏兼容:如果需要实现无标题栏的全屏,可以在全屏前解锁窗口,进入全屏后锁定;退出全屏后恢复锁定(根据需求调整on_configure中的状态判断即可)

依赖安装

  • Linux下需要安装python-xlib:pip install python-xlib
  • MacOS下需要安装pyobjc-framework-Quartz:pip install pyobjc-framework-Quartz
  • Windows下无需额外安装,ctypes是标准库的一部分

内容的提问来源于stack exchange,提问作者TheGreenLightning444

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:20:35