2010-07-28 13 views
36

Ich versuche ein Tkinter-Fenster zu zentrieren. Ich weiß, dass ich programmatisch die Größe des Fensters und die Größe des Bildschirms erhalten und damit die Geometrie einstellen kann, aber ich frage mich, ob es eine einfachere Möglichkeit gibt, das Fenster auf dem Bildschirm zu zentrieren.Wie zentriert man ein Fenster auf dem Bildschirm in Tkinter?

Antwort

54

Sie können versuchen, die Methoden zu verwenden winfo_screenwidth und winfo_screenheight, die jeweils die Breite und Höhe (in Pixeln) Ihre Tk Instanz (Fenster), und mit einigen grundlegenden mathematischen zurückkehren können Sie Ihre Fenster zentrieren:

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

Ich rufe update_idletasks Methode vor dem Abrufen der Breite und der Höhe des Fensters, um sicherzustellen, dass die zurückgegebenen Werte genau sind.

+13

"nicht am stärksten" ist ein bisschen subjektiv. Es hat so viel "Power" wie andere Toolkits (abhängig von Ihrer Definition von "Power"), es macht einfach nicht so viel Hand-halten. Es ist der Unterschied zwischen dem Bauen eines Hauses mit vorgefertigten Wänden (einige andere Toolkits) oder dem Bauen aus einem Holzhaufen (Tk). Du kannst in Tkinter so ziemlich alles machen, was du in anderen Toolkits tun kannst, du musst nur manchmal ein wenig dafür arbeiten. –

+0

Scheint meinen Verdacht zu bestätigen, danke! – psicopoo

+4

@Bryan - genau das meine ich mit Macht. Klar, man kann mit einem Yugo (vielleicht) und einem Ferrari quer durch die Vereinigten Staaten fahren, aber einer von ihnen kann dich viel schneller dorthin bringen. Natürlich haben beide die Möglichkeit, auf bestimmte Arten mit dem Benutzer zu interagieren, aber Tkinter hat nicht die Kraft, größere Programme in weniger Zeilen (und mit weniger Aufwand) schreiben zu können. Natürlich sind kleinere Programme in Tkinter tatsächlich einfacher, da Sie sich nicht um dieselben Overhead-Widgets kümmern müssen wie andere Toolkits, und das ist es, wofür ich Tkinter liebe - kleinere Programme zu schreiben. @psicopoo, gern geschehen! –

28

Der allgemeine Ansatz, ein Fenster zu zentrieren ist die entsprechenden Bildschirmkoordinaten für das Fenster der oberen linken Pixel zu berechnen:

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

Dies ist jedoch nicht ausreichend für genau eine tkinter Fensterzentrierung (zumindest unter Windows 7);
weil die Breite und Höhe des Fensters von zurückgegeben werden, enthält keine Methode den äußersten Rahmen mit den Titeln und Min/Max/Schließen-Schaltflächen. Es wird auch keine menu bar (mit Datei, Bearbeiten, etc.) enthalten. Zum Glück gibt es einen Weg, um die Dimensionen von diesen zu finden.

Hier ist die grundlegende Funktion, die nicht die oben genannte Problem nicht berücksichtigt:

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

Alternativen: winfo_reqwidth(), winfo_reqheight()

An erster Stelle wollen wir die update_idletasks() Methode
Fenster aufzurufen direkt vor dem Abrufen einer Geometrie, um sicherzustellen, dass die zurückgegebenen Werte korrekt sind.

Es ist wichtig zu verstehen, die geometry strings mit der geometry() Methode verwendet.
Die erste Hälfte ist die Breite und Höhe des Fensters ohne der äußere Rahmen,
und die zweite Hälfte ist die oberen linken X- und Y-Koordinaten des äußeren Rahmens.

Es gibt vier Methoden, mit denen wir die Abmessungen des äußeren Rahmens bestimmen können.
winfo_rootx() gibt uns die obere linke X-Koordinate des Fensters, ohne den äußeren Rahmen.
winfo_x() wird uns die obere linke X-Koordinate des äußeren Rahmens geben.
Ihr Unterschied ist die Breite des äußeren Rahmens.

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

Der Unterschied zwischen winfo_rooty() und winfo_y() werden unsere Titel-Bar/Menüleiste der Höhe sein.Hier

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

ist die komplette Funktion, in einem Arbeitsbeispiel:

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

Ein Weg, über den Bildschirm das Fenster bewegen zu verhindern, sehen verwenden .attributes('-alpha', 0.0) das Fenster vollständig transparent und stellen Sie dann zu machen es zu 1.0 nachdem das Fenster zentriert wurde. Mit withdraw() oder iconify() später gefolgt von deiconify() scheint nicht gut zu diesem Zweck unter Windows 7 zu funktionieren. Beachten Sie, dass ich deiconify() als einen Trick verwenden, um das Fenster zu aktivieren.

+0

Es sieht so aus, als ob die zentrale Funktion nicht in rohen X11 über SSH funktioniert, unter Windows über Xming. Scheint sich an die standardmäßige Formularplatzierung von Window zu halten, beginnend von oben links. Die Geometrieausgabe sieht korrekt aus, aber es ist möglich, dass irgendeine Interaktion mit Xming nicht funktioniert? – Kumba

+0

der -alpha Trick scheint nicht in Linux zu funktionieren. Ich bin mir nicht sicher, was ich sonst noch tun kann. –

15

Tk bietet eine Hilfsfunktion, die dies als tk::PlaceWindow tun kann, aber ich glaube nicht, dass es als eine umhüllte Methode in Tkinter ausgesetzt wurde. Sie würden ein Widget mit dem folgende Zentrum:

from tkinter import * 

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

Diese Funktion mit mehreren Displays korrekt als auch umgehen sollte. Es hat auch Optionen, um sich über einem anderen Widget oder relativ zum Zeiger zu zentrieren (wird zum Platzieren von Popup-Menüs verwendet), so dass sie nicht vom Bildschirm fallen.

+1

Leider berücksichtigt es nicht den äußeren Rahmen mit dem Titel und dem Schließen-Knopf; also ist es immer noch nicht vollständig zentriert (zumindest unter Windows 7). Dies ist die kurze Alternative zu Wayne's Antwort. +1, um dies zu verdeutlichen. Vielleicht können wir es von den Tk-Entwicklern aktualisieren lassen. –

+0

winfo_Pfadname schlägt auf Python 3.5.1 (auf Win10) mit '_tkinter.TclError fehl: Fenster ID" 2885868 "existiert nicht in dieser Anwendung'. Ich glaube nicht, dass ich jemals an Python 3 gearbeitet habe, aber von deinem Kleinbuchstabenimport nehme ich an, dass es für dich funktioniert hat? Ich konnte den Code aktualisieren, indem ich wfino_topelev stattdessen benutze: 'app.eval ('tk :: PlaceWindow% s center'% app.winfo_toplevel())' – idbrii

0

Ich verwende Frame und erweitern Option. Sehr einfach. Ich möchte einige Tasten in der Mitte des Bildschirms. Größe Fenster und Schaltfläche bleiben in der Mitte. Das ist meine Lösung.

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

ich eine Lösung für die gleiche Frage 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() 

sicher gefunden haben, ich es entsprechend meine Zwecke geändert, es funktioniert.