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

Tkinter Simpledialog中AskOkCancel对话框定位失效及lift必要性咨询

自定义Tkinter Dialog的两个问题解决

问题描述

  1. 基于tkinter.simpledialog.Dialog自定义AskOkCancel对话框时,调用.geometry()设置窗口位置,仅WxH尺寸部分生效,+X+Y坐标部分完全无效。
  2. 若不添加self.lift(aboveThis=self.parent)语句,对话框会被root主窗口遮挡,需确认该语句是否必须。

使用环境:Python 3.9.2、Debian GNU/Linux 11(bullseye)

解决方案

1. 坐标设置无效的修复

原因是Dialog类的__init__方法最后会自动调用默认的position()方法,该方法会强制将窗口居中,覆盖你在body里设置的坐标。

解决方法:重写Dialog的position方法,将你的居中逻辑放在这里,替代默认行为:

class AskOkCancel(Dialog):
    def __init__(self, parent, title, message=None):
        self.message = message
        self.parent = parent
        super().__init__(parent, title)

    def _center(self, parent):
        """Center self over parent"""
        def _getxy(w):
            return w.winfo_rootx(), w.winfo_rooty()

        def _getwh(w):
            return w.winfo_width(), w.winfo_height()

        def _getreqwh(w):
            return w.winfo_reqwidth(), w.winfo_reqheight()

        self.update_idletasks()
        xo, yo = _getxy(parent)
        wo, ho = _getwh(parent)
        wi, hi = _getreqwh(self)
        # 'wxh±x±y'
        self.geometry('+{:d}+{:d}'.format(
            xo + (wo - wi) // 2, yo + (ho - hi) // 2))

    # 重写position方法,替换默认居中逻辑
    def position(self):
        self._center(self.parent)

    def body(self, box):
        tk.Label(box, text=textwrap.fill(self.message, width=40), height=3,
                 relief=tk.SUNKEN).grid(column=0, columnspan=2, row=0)
        self.chkvar = tk.IntVar()
        self.chk = tk.Checkbutton(box, variable=self.chkvar,
                                  text="Remember my answer")
        self.chk.grid(column=0, row=1, columnspan=2, sticky=tk.EW)
        self.result = False, None
        return self.chk              # initial focus

    def apply(self):
        self.result = True, self.chkvar.get()

2. 对话框被遮挡的问题解决

self.lift(aboveThis=self.parent)在你的环境下确实能解决遮挡,但更规范且跨平台可靠的方式是设置窗口为父窗口的临时窗口(transient),这会让窗口管理器自动保证对话框在父窗口上方。

修改__init__方法,添加self.transient(parent):

def __init__(self, parent, title, message=None):
    self.message = message
    self.parent = parent
    super().__init__(parent, title)
    self.transient(parent)  # 添加这行,替代lift语句

这样就可以移除body里的self.lift(aboveThis=self.parent)语句,同时避免对话框被遮挡。如果设置transient后仍有问题(极少数窗口管理器环境),再保留self.lift语句作为补充,但优先用transient。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 15:48:31