Tkinter Simpledialog中AskOkCancel对话框定位失效及lift必要性咨询
自定义Tkinter Dialog的两个问题解决
问题描述
- 基于
tkinter.simpledialog.Dialog自定义AskOkCancel对话框时,调用.geometry()设置窗口位置,仅WxH尺寸部分生效,+X+Y坐标部分完全无效。 - 若不添加
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
相关产品推荐
相关产品推荐

