2010-07-28 27 views
36

Bir titreme penceresi ortalamaya çalışıyorum. Pencerenin boyutunu ve ekranın boyutunu programlanabilir hale getirebileceğimi ve geometriyi ayarlamak için kullanabileceğimi biliyorum, ancak pencereyi ekranda ortalamanın daha basit bir yolu olup olmadığını merak ediyorum.Tkinter'da ekran üzerinde bir pencere nasıl ortalanır?

cevap

54

Sen Tk örneğinin (piksel) sırasıyla genişliği ve yüksekliği dönmek yöntemleri winfo_screenwidth ve winfo_screenheight, (pencere) kullanmayı deneyebilirsiniz, ve bazı temel matematik ile size penceresini ortalayabilirsiniz:

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

Döndürülen değerlerin doğru olduğundan emin olmak için pencerenin genişliğini ve yüksekliğini almadan önce update_idletasks yöntemini arıyorum.

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

Ancak bu doğru bir Tkinter pencere merkezleme yeterli değildir olup:

+13

"En güçlü değil" biraz özneldir. Diğer araçların ("güç" tanımınıza bağlı olarak) olduğu kadar "güç" de vardır, bu sadece el ele tutuşmaz. Önceden yapılmış duvarlara sahip bir ev inşa etmek (bazı diğer alet takımları) veya kereste (Tk) yığınından inşa etmek arasındaki fark bu. Tkinter'de diğer araç takımlarında yapabileceğiniz pek çok şey yapabilirsiniz, sadece bunun için biraz çalışmak zorundasınız. –

+0

Şüphelerimi onaylamak için teşekkürler, teşekkürler! – psicopoo

+4

@Bryan - tam olarak ne demek istediğimi kastediyorum. Bir Yugo (belki) ve bir Ferrari'de Amerika Birleşik Devletleri'ne girebildiğinize emin olun, ancak bunlardan biri sizi çok daha hızlı bir hale getirebilir. Tabii ki, her ikisi de, kullanıcıyla belirli şekillerde etkileşimde bulunma gücüne sahiptir, fakat Tkinter, daha az sayıda programla daha az sayıda program yazmanıza izin verme gücüne sahip değildir (ve daha az çaba ile). Tabii ki, Tkinter'de daha küçük programlar gerçekten daha kolay çünkü diğer araç takımları gibi widget'lar için aynı yük hakkında endişelenmenize gerek yok, ve ben daha küçük programları yazmak için Tkinter'i seviyorum. @psicopoo, rica ederim! –

28

bir pencere merkezleme genel yaklaşım, uygun ekran penceresinin üst sol piksel için koordinatları hesaplamaktır (en az Windows 7'de);
tarafından döndürülen pencerenin genişliği ve yüksekliği herhangi bir yönteminde başlık ve min/maks/kapat düğmeleriyle en dış çerçeveyi içermeyecektir. Ayrıca bir menu bar (Dosya, Düzen vb. Ile birlikte) içermeyecektir. Neyse ki bunların boyutlarını bulmak için bir yol var.

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

Alternatifler: Burada

yukarıda belirtilen konuyu dikkate almaz en temel fonksiyonu vardır winfo_reqwidth(), winfo_reqheight()

Öncelikle ve en önemlisi, biz pencerenin update_idletasks() yöntem aramak istediğiniz
Herhangi bir geometriyi almadan önce, döndürülen değerlerin doğru olduğundan emin olmak için.

geometry() yöntemiyle kullanılan geometry strings değerini anlamak önemlidir.
İlk yarısı, dış çerçevenin dış çerçevesi,
hariç ikinci genişlik ve yükseklik ve ikinci yarısı dış çerçevenin sol üst x ve y koordinatlarıdır.

Dış çerçevenin boyutlarını belirlememize olanak tanıyan dört yöntem vardır.
winfo_rootx(), dış çerçevede
hariç, pencerenin sol üst x koordinatını, 'u verecektir.
winfo_x() bize dış çerçevenin sol üst x koordinatını verecektir.
Aralarındaki fark dış çerçevenin genişliğidir.

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

winfo_rooty() ve winfo_y() arasındaki fark bizim başlık çubuğu/menünün-barın yüksekliği olacak.ekran boyunca pencere hareket pencere tamamen şeffaf ve daha sonra set yapmak için .attributes('-alpha', 0.0) kullanmaktır görmeye önlemek için

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

Tek yönlü: Burada

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

bir çalışma örneğinde, tam fonksiyondur pencere ortalandıktan sonra 1.0'a. veya iconify() öğelerini ve ardından deiconify() öğelerini uygulamayın, bu amaçla, Windows 7'de düzgün çalışmıyor gibi görünüyor. Bu pencereyi etkinleştirmek için deiconify() numarasını kullandığımı unutmayın.

+0

Merkezi işlev Xlight üzerinden Windows'ta SSH üzerinden ham X11'de çalışmıyor gibi görünüyor. Üst soldan başlayarak, Window'un standart form yerleşimine bağlı kalıyor. Geometri çıktı doğru görünüyor, ancak Xming ile bir tür etkileşim çalışmıyor mu? – Kumba

+0

-alpha trick, Linux'ta çalışmıyor gibi görünüyor. Başka ne yapabileceğime emin değilim. –

15

Tk, bunu tk::PlaceWindow olarak yapabilen bir yardımcı işlev sağlar, ancak Tkinter'da sarılmış bir yöntem olarak gösterildiğine inanmıyorum. Aşağıdaki kullanarak bir widget ortalamak olacaktır:

from tkinter import * 

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

Bu fonksiyon, doğru yanı çoklu ekran ile uğraşmak gerekir. Ayrıca, ekrandan düşmemeleri için işaretçiye (açılır menülerin yerleştirilmesinde kullanılır) göre başka bir pencere aracının üzerine veya ortalamasına göre seçenekler de vardır.

+1

Maalesef, dış çerçeveyi başlık ve kapatma düğmesiyle düşünmüyor; Bu yüzden hala tam olarak ortalanmış değil (en az Windows 7'de). Bu Wayne'in cevabının kısa alternatifi. Bunu getirmek için +1. Belki de Tk geliştiricileri tarafından yükseltilebilir. –

+0

winfo_pathname, Python 3.5.1'de (Win10 üzerinde) '_tkinter.TclError: window id" 2885868 "bu uygulamada mevcut değil. Bunun Python 3 üzerinde çalıştığını sanmıyorum, ama küçük harfli ithalatınızdan, sizin için çalıştığını düşünüyorum. Kodunu winfo_toplevel yerine güncelleyebildim: 'app.eval (' tk :: PlaceWindow% s center '% app.winfo_toplevel()) ' – idbrii

0

Çerçeve kullanıyorum ve seçeneği genişletin. Çok basit. Ekranın ortasında bazı düğmeler istiyorum. Pencereyi yeniden boyutlandır ve buton ortada kalır. Bu benim çözümüm.

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

Aynı soruya emin 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() 

için bir çözüm bulduk, ben buna benim amaçlar için değiştirildi, işe yarıyor.

İlgili konular