Общий подход к центрированию окна заключается в вычислении соответствующих координат экрана для верхнего левого пикселя окна:
x = (screen_width / 2) - (window_width / 2)
y = (screen_height / 2) - (window_height / 2)
Однако этого не достаточно для точного центрирования окна tkinter (по крайней мере, в Windows 7);
потому что ширина и высота окна, возвращаемые методом any , не будут включать в себя самый внешний кадр с кнопками title и min / max / close.
Он также не будет содержать строку меню (с File, Edit и т. Д.). К счастью есть способ найти их размеры.
Вот самая основная функция, которая не учитывает вышеупомянутую проблему:
def center(win):
win.update_idletasks()
width = win.winfo_width()
height = win.winfo_height()
x = (win.winfo_screenwidth() // 2) - (width // 2)
y = (win.winfo_screenheight() // 2) - (height // 2)
win.geometry('{}x{}+{}+{}'.format(width, height, x, y))
Альтернативы: winfo_reqwidth()
, winfo_reqheight()
Прежде всего, мы хотим вызвать метод update_idletasks()
окна
непосредственно перед извлечением любой геометрии, чтобы обеспечить точность возвращаемых значений.
Важно понимать геометрические строки , используемые с методом geometry()
.
Первая половина - ширина и высота окна , исключая внешнюю раму,
а вторая половина - это верхние левые координаты x и y внешнего кадра.
Существует четыре метода, которые позволят нам определить размеры внешнего каркаса.
winfo_rootx()
даст нам верхнюю левую координату x окна, исключая внешнюю рамку.
winfo_x()
даст нам верхнюю левую координату x внешней рамки.
Их разница в ширине внешней рамки.
frm_width = win.winfo_rootx() - win.winfo_x()
win_width = win.winfo_width() + (2*frm_width)
Разница между winfo_rooty()
и winfo_y()
будет высотой строки заголовка / строки меню.
titlebar_height = win.winfo_rooty() - win.winfo_y()
win_height = win.winfo_height() + (titlebar_height + frm_width)
Вот полная функция в рабочем примере:
import tkinter # Python 3
def center(win):
"""
centers a tkinter window
:param win: the root or Toplevel window to center
"""
win.update_idletasks()
width = win.winfo_width()
frm_width = win.winfo_rootx() - win.winfo_x()
win_width = width + 2 * frm_width
height = win.winfo_height()
titlebar_height = win.winfo_rooty() - win.winfo_y()
win_height = height + titlebar_height + frm_width
x = win.winfo_screenwidth() // 2 - win_width // 2
y = win.winfo_screenheight() // 2 - win_height // 2
win.geometry('{}x{}+{}+{}'.format(width, height, x, y))
win.deiconify()
if __name__ == '__main__':
root = tkinter.Tk()
root.attributes('-alpha', 0.0)
menubar = tkinter.Menu(root)
filemenu = tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=root.destroy)
menubar.add_cascade(label="File", menu=filemenu)
root.config(menu=menubar)
frm = tkinter.Frame(root, bd=4, relief='raised')
frm.pack(fill='x')
lab = tkinter.Label(frm, text='Hello World!', bd=4, relief='sunken')
lab.pack(ipadx=4, padx=4, ipady=4, pady=4, fill='both')
center(root)
root.attributes('-alpha', 1.0)
root.mainloop()
Одним из способов предотвращения движения окна по экрану является использование
.attributes('-alpha', 0.0)
, чтобы сделать окно полностью прозрачным, а затем установить его на 1.0
после того, как окно было отцентрировано. Использование withdraw()
или iconify()
позже, за которым следует deiconify()
, похоже, не очень хорошо подходит для этой цели в Windows 7. Обратите внимание, что я использую deiconify()
в качестве трюка для активации окна.