From c6c43b28746b0642cc3c49dd8138b896bed3028f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 24 Dec 2020 20:26:28 +0200 Subject: [PATCH] bpo-42685: Improve placing of simple query windows. (GH-23856) * If parent is specified and mapped, the query widget is centered at the center of parent. Its position and size can be corrected so that it fits in the virtual root window. * Otherwise it is centered at the center of the screen. --- Lib/tkinter/simpledialog.py | 69 +++++++++---------- .../2020-12-19-17-32-43.bpo-42685.kwZlwp.rst | 4 ++ 2 files changed, 38 insertions(+), 35 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-19-17-32-43.bpo-42685.kwZlwp.rst diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py index b882d47c961..638da87c876 100644 --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -55,36 +55,8 @@ class SimpleDialog: b.config(relief=RIDGE, borderwidth=8) b.pack(side=LEFT, fill=BOTH, expand=1) self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window) - self._set_transient(master) - - def _set_transient(self, master, relx=0.5, rely=0.3): - widget = self.root - widget.withdraw() # Remain invisible while we figure out the geometry - widget.transient(master) - widget.update_idletasks() # Actualize geometry information - if master.winfo_ismapped(): - m_width = master.winfo_width() - m_height = master.winfo_height() - m_x = master.winfo_rootx() - m_y = master.winfo_rooty() - else: - m_width = master.winfo_screenwidth() - m_height = master.winfo_screenheight() - m_x = m_y = 0 - w_width = widget.winfo_reqwidth() - w_height = widget.winfo_reqheight() - x = m_x + (m_width - w_width) * relx - y = m_y + (m_height - w_height) * rely - if x+w_width > master.winfo_screenwidth(): - x = master.winfo_screenwidth() - w_width - elif x < 0: - x = 0 - if y+w_height > master.winfo_screenheight(): - y = master.winfo_screenheight() - w_height - elif y < 0: - y = 0 - widget.geometry("+%d+%d" % (x, y)) - widget.deiconify() # Become visible at the desired location + self.root.transient(master) + _place_window(self.root, master) def go(self): self.root.wait_visibility() @@ -157,11 +129,7 @@ class Dialog(Toplevel): self.protocol("WM_DELETE_WINDOW", self.cancel) - if parent is not None: - self.geometry("+%d+%d" % (parent.winfo_rootx()+50, - parent.winfo_rooty()+50)) - - self.deiconify() # become visible now + _place_window(self, parent) self.initial_focus.focus_set() @@ -251,6 +219,37 @@ class Dialog(Toplevel): pass # override +# Place a toplevel window at the center of parent or screen +# It is a Python implementation of ::tk::PlaceWindow. +def _place_window(w, parent=None): + w.wm_withdraw() # Remain invisible while we figure out the geometry + w.update_idletasks() # Actualize geometry information + + minwidth = w.winfo_reqwidth() + minheight = w.winfo_reqheight() + maxwidth = w.winfo_vrootwidth() + maxheight = w.winfo_vrootheight() + if parent is not None and parent.winfo_ismapped(): + x = parent.winfo_rootx() + (parent.winfo_width() - minwidth) // 2 + y = parent.winfo_rooty() + (parent.winfo_height() - minheight) // 2 + vrootx = w.winfo_vrootx() + vrooty = w.winfo_vrooty() + x = min(x, vrootx + maxwidth - minwidth) + x = max(x, vrootx) + y = min(y, vrooty + maxheight - minheight) + y = max(y, vrooty) + if w._windowingsystem == 'aqua': + # Avoid the native menu bar which sits on top of everything. + y = max(y, 22) + else: + x = (w.winfo_screenwidth() - minwidth) // 2 + y = (w.winfo_screenheight() - minheight) // 2 + + w.wm_maxsize(maxwidth, maxheight) + w.wm_geometry('+%d+%d' % (x, y)) + w.wm_deiconify() # Become visible at the desired location + + # -------------------------------------------------------------------- # convenience dialogues diff --git a/Misc/NEWS.d/next/Library/2020-12-19-17-32-43.bpo-42685.kwZlwp.rst b/Misc/NEWS.d/next/Library/2020-12-19-17-32-43.bpo-42685.kwZlwp.rst new file mode 100644 index 00000000000..068546a34c5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-19-17-32-43.bpo-42685.kwZlwp.rst @@ -0,0 +1,4 @@ +Improved placing of simple query windows in Tkinter (such as +:func:`tkinter.simpledialog.askinteger`). They are now centered at the +center of the parent window if it is specified and shown, otherwise at the +center of the screen.