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

如何将CustomTkinter窗口的坐标原点设置为左上角?

解决CustomTkinter窗口定位到右上角的坐标问题

问题原因

当调用root.overrideredirect(True)移除窗口装饰后,CustomTkinter(底层基于Tkinter)的窗口几何计算逻辑会发生变化——此时直接用固定的窗口宽度值计算位置,会出现坐标参考点偏移的问题,表现为窗口中心对齐到屏幕右侧而非左上角对齐。这是无装饰窗口的特殊渲染特性导致的。

正确解决方法

方法1:动态获取窗口实际宽度

先强制窗口完成布局更新,再获取真实的窗口宽度来计算右上角坐标,避免固定值偏差:

def click_but():
    TimeEntry.pack_forget()
    StartButton.pack_forget()
    hours = int(TimeEntry.get()[:2])
    minutes = int(TimeEntry.get()[3:5])
    seconds = int(TimeEntry.get()[6:])
    
    root.overrideredirect(True)
    root.geometry("500x100")
    # 强制更新布局,确保获取到真实窗口尺寸
    root.update_idletasks()
    # 计算右上角坐标:屏幕宽度 - 窗口实际宽度,y轴设为0
    x_pos = root.winfo_screenwidth() - root.winfo_width()
    root.geometry(f"+{x_pos}+0")
    
    # 后续计时逻辑...

方法2:合并窗口大小与位置设置

直接在一个geometry调用中同时指定窗口尺寸和位置,避免分开设置导致的布局延迟问题:

def click_but():
    TimeEntry.pack_forget()
    StartButton.pack_forget()
    hours = int(TimeEntry.get()[:2])
    minutes = int(TimeEntry.get()[3:5])
    seconds = int(TimeEntry.get()[6:])
    
    root.overrideredirect(True)
    win_width = 500
    win_height = 100
    x_pos = root.winfo_screenwidth() - win_width
    # 合并设置尺寸与位置
    root.geometry(f"{win_width}x{win_height}+{x_pos}+0")
    
    # 后续计时逻辑...

额外优化:替换阻塞式计时逻辑

原代码中while循环+time.sleep(1)会阻塞Tkinter主事件循环,导致窗口卡顿无响应。建议改用root.after()实现非阻塞式倒计时:

def countdown(hours, minutes, seconds):
    if hours < 0:
        # 计时结束恢复窗口状态
        root.geometry("500x250")
        TimeEntry.pack(side='top')
        StartButton.pack(side='top', pady=10)
        root.overrideredirect(False)
        return
    
    # 格式化时间字符串
    time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
    TimeLabel.configure(text=time_str)
    
    # 计算下一秒的时间参数
    seconds -= 1
    if seconds < 0:
        seconds = 59
        minutes -= 1
        if minutes < 0:
            minutes = 59
            hours -= 1
    
    # 1秒后递归调用自身
    root.after(1000, countdown, hours, minutes, seconds)

完整优化后的代码

import customtkinter as ctk

def countdown(hours, minutes, seconds):
    if hours < 0:
        root.geometry("500x250")
        TimeEntry.pack(side='top')
        StartButton.pack(side='top', pady=10)
        root.overrideredirect(False)
        return
    
    time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
    TimeLabel.configure(text=time_str)
    
    seconds -= 1
    if seconds < 0:
        seconds = 59
        minutes -= 1
        if minutes < 0:
            minutes = 59
            hours -= 1
    
    root.after(1000, countdown, hours, minutes, seconds)

def click_but():
    TimeEntry.pack_forget()
    StartButton.pack_forget()
    try:
        hours = int(TimeEntry.get()[:2])
        minutes = int(TimeEntry.get()[3:5])
        seconds = int(TimeEntry.get()[6:])
    except (IndexError, ValueError):
        TimeLabel.configure(text="输入格式错误")
        TimeEntry.pack(side='top')
        StartButton.pack(side='top', pady=10)
        return
    
    root.overrideredirect(True)
    win_width = 500
    win_height = 100
    x_pos = root.winfo_screenwidth() - win_width
    root.geometry(f"{win_width}x{win_height}+{x_pos}+0")
    
    countdown(hours, minutes, seconds)

root = ctk.CTk()
root.geometry("500x250")

TimeLabel = ctk.CTkLabel(master=root, text='00:00:00', font=('Segoe UI', 100))
TimeLabel.pack(side='top')
TimeEntry = ctk.CTkEntry(master=root, font=('Segoe UI', 50), width=300, justify="center")
TimeEntry.pack(side='top')
StartButton = ctk.CTkButton(master=root, text='Start', command=click_but, font=('Segoe UI', 50))
StartButton.pack(side='top', pady=10)

root.mainloop()

内容的提问来源于stack exchange,提问作者Денис Шпак

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:07:42