2010-07-28 76 views

Trả lời

54

Bạn có thể cố gắng sử dụng các phương pháp winfo_screenwidthwinfo_screenheight, mà quay trở lại tương ứng với chiều rộng và chiều cao (tính bằng pixel) của Tk dụ của bạn (cửa sổ), và với một số thuật toán cơ bản bạn có thể tập trung cửa sổ của bạn:

import tkinter as tk 


def center(toplevel): 
    toplevel.update_idletasks() 
    w = toplevel.winfo_screenwidth() 
    h = toplevel.winfo_screenheight() 
    size = tuple(int(_) for _ in toplevel.geometry().split('+')[0].split('x')) 
    x = w/2 - size[0]/2 
    y = h/2 - size[1]/2 
    toplevel.geometry("%dx%d+%d+%d" % (size + (x, y))) 


if __name__ == '__main__': 
    root = tk.Tk() 
    root.title("Not centered") 

    win = tk.Toplevel(root) 
    win.title("Centered!") 
    center(win) 

    root.mainloop() 

Tôi đang gọi phương thức update_idletasks trước khi truy xuất chiều rộng và chiều cao của cửa sổ để đảm bảo rằng các giá trị được trả về là chính xác.

+13

"không mạnh nhất" là một chút chủ quan. Nó có nhiều "sức mạnh" như các bộ công cụ khác (tùy thuộc vào định nghĩa của bạn về "sức mạnh"), nó chỉ không làm nhiều việc cầm tay. Đó là sự khác biệt giữa việc xây dựng một ngôi nhà với các bức tường được làm sẵn (một số bộ công cụ khác) hoặc xây dựng nó từ một đống gỗ (Tk). Bạn có thể làm bất cứ điều gì trong Tkinter mà bạn có thể làm trong các bộ công cụ khác, đôi khi bạn phải làm việc một chút. –

+0

Dường như để xác nhận sự nghi ngờ của tôi, cảm ơn! – psicopoo

+4

@Bryan - đó là chính xác những gì tôi có ý nghĩa bởi quyền lực. Chắc chắn bạn có thể đi qua Hoa Kỳ trong một Yugo (có thể) và một chiếc Ferrari, nhưng một trong số họ có thể giúp bạn có rất nhiều nhanh hơn. Tất nhiên cả hai đều có khả năng tương tác với người dùng theo những cách nhất định, nhưng Tkinter không có khả năng cho phép bạn viết các chương trình lớn hơn trong ít dòng hơn (và ít nỗ lực hơn). Tất nhiên, các chương trình nhỏ hơn thực sự dễ dàng hơn trong Tkinter bởi vì bạn không phải lo lắng về cùng một chi phí cho các widget như các bộ công cụ khác, và đó là những gì tôi yêu Tkinter cho - viết các chương trình nhỏ hơn. @psicopoo, bạn được chào đón! –

28

Cách tiếp cận chung để tập trung một cửa sổ là để tính toán màn hình thích hợp phối cho điểm ảnh trên bên trái của cửa sổ:

x = (screen_width/2) - (window_width/2) 
y = (screen_height/2) - (window_height/2) 

Tuy nhiên, đây là không đủ cho chính xác trung một cửa sổ Tkinter (trên Windows 7 ít nhất);
vì chiều rộng và chiều cao của cửa sổ được trả về bởi bất kỳ phương pháp nào sẽ không bao gồm khung ngoài cùng, với tiêu đề và nút tối thiểu/tối đa/đóng. Nó cũng sẽ không bao gồm menu bar (với Tệp, Chỉnh sửa, v.v.). May mắn thay có một cách để tìm kích thước của chúng.

Dưới đây là chức năng cơ bản nhất, mà không xem xét vấn đề nói trên:

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)) 

Alternatives: winfo_reqwidth(), winfo_reqheight()

Thứ nhất, và quan trọng nhất, chúng tôi muốn gọi phương thức của cửa sổ update_idletasks()
trực tiếp trước khi lấy bất kỳ hình học nào, để đảm bảo rằng các giá trị được trả về là chính xác.

Điều quan trọng là phải hiểu được geometry strings được sử dụng với phương pháp geometry().
Nửa đầu là chiều rộng và chiều cao của cửa sổ trừ khung bên ngoài,
và nửa thứ hai là tọa độ x và y trên cùng bên trái của khung bên trái.

Có bốn phương pháp sẽ cho phép chúng tôi xác định thứ nguyên của khung bên ngoài.
winfo_rootx() sẽ cho chúng tôi tọa độ x bên trái trên cùng của cửa sổ, trừ khung bên ngoài.
winfo_x() sẽ cho chúng ta tọa độ x bên trái trên cùng của khung bên ngoài.
Sự khác biệt của chúng là chiều rộng của khung bên ngoài.

frm_width = win.winfo_rootx() - win.winfo_x() 
win_width = win.winfo_width() + (2*frm_width) 

Sự khác biệt giữa winfo_rooty()winfo_y() sẽ chiều cao tiêu đề-bar của chúng tôi/menu-thanh của.

titlebar_height = win.winfo_rooty() - win.winfo_y() 
win_height = win.winfo_height() + (titlebar_height + frm_width) 

Dưới đây là chức năng hoàn chỉnh, trong một ví dụ làm việc:

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() 

Một cách để ngăn chặn nhìn thấy di chuyển cửa sổ trên màn hình là sử dụng .attributes('-alpha', 0.0) để làm cho cửa sổ hoàn toàn trong suốt và sau đó đặt nó đến 1.0 sau khi cửa sổ được căn giữa. Sử dụng withdraw() hoặc iconify() sau đó theo sau là deiconify() dường như không hoạt động tốt, vì mục đích này, trên Windows 7. Lưu ý rằng tôi sử dụng deiconify() làm mẹo để kích hoạt cửa sổ.

+0

Có vẻ như chức năng trung tâm không hoạt động trong X11 thô qua SSH, trên Windows thông qua Xming. Dường như tuân theo vị trí biểu mẫu chuẩn của Window, bắt đầu từ trên cùng bên trái. Sản lượng hình học có vẻ chính xác, nhưng có thể một số loại tương tác với Xming không hoạt động? – Kumba

+0

mẹo -alpha dường như không hoạt động trong Linux. Không chắc tôi có thể làm gì khác. –

15

Tk cung cấp chức năng trợ giúp có thể thực hiện điều này dưới dạng tk::PlaceWindow, nhưng tôi không tin rằng nó đã được hiển thị dưới dạng phương thức gói trong Tkinter. Bạn sẽ căn giữa tiện ích bằng cách sử dụng các mục sau:

from tkinter import * 

app = Tk() 
app.eval('tk::PlaceWindow %s center' % app.winfo_pathname(app.winfo_id())) 
app.mainloop() 

Chức năng này cũng nên xử lý nhiều màn hình chính xác. Nó cũng có các tùy chọn để tập trung vào một widget khác hoặc tương đối so với con trỏ (được sử dụng để đặt các menu popup), để chúng không rơi ra khỏi màn hình.

+1

Thật không may nó không xem xét khung bên ngoài với tiêu đề và nút đóng; do đó, nó vẫn không hoàn toàn tập trung (trên Windows 7 ít nhất). Đây là giải pháp thay thế ngắn cho câu trả lời của Wayne. 1 cho việc này mặc dù. Có lẽ chúng ta có thể làm cho nó được nâng cấp bởi các nhà phát triển Tk. –

+0

winfo_pathname thất bại trên Python 3.5.1 (trên Win10) với '_tkinter.TclError: window id" 2885868 "không tồn tại trong ứng dụng này'. Tôi không nghĩ rằng tôi đã từng làm việc này trên Python 3, nhưng từ trường hợp nhập thấp hơn của bạn, tôi giả sử nó làm việc cho bạn? Tôi đã có thể cập nhật mã bằng cách sử dụng winfo_toplevel thay vào đó: 'app.eval ('tk :: PlaceWindow% s center'% app.winfo_toplevel())' – idbrii

0

Tôi sử dụng tùy chọn khung và mở rộng. Rất đơn giản. Tôi muốn một số nút ở giữa màn hình. Thay đổi kích thước cửa sổ và nút ở giữa. Đây là giải pháp của tôi.

frame = Frame(parent_window) 
Button(frame, text='button1', command=command_1).pack(fill=X) 
Button(frame, text='button2', command=command_2).pack(fill=X) 
Button(frame, text='button3', command=command_3).pack(fill=X) 
frame.pack(anchor=CENTER, expand=1) 
1

Tôi đã tìm thấy một giải pháp cho cùng một câu hỏi on this site

from tkinter import Tk 
from tkinter.ttk import Label 
root = Tk() 
Label(root, text="Hello world").pack() 

# Apparently a common hack to get the window size. Temporarily hide the 
# window to avoid update_idletasks() drawing the window in the wrong 
# position. 
root.withdraw() 
root.update_idletasks() # Update "requested size" from geometry manager 

x = (root.winfo_screenwidth() - root.winfo_reqwidth())/2 
y = (root.winfo_screenheight() - root.winfo_reqheight())/2 
root.geometry("+%d+%d" % (x, y)) 

# This seems to draw the window frame immediately, so only call deiconify() 
# after setting correct window position 
root.deiconify() 
root.mainloop() 

chắc chắn, tôi đã thay đổi nó tương ứng với các mục đích của tôi, nó hoạt động.

Các vấn đề liên quan