Text in Label gleich ausrichten

Fragen zu Tkinter.
Antworten
Benutzeravatar
MrCrowncoin
User
Beiträge: 3
Registriert: Freitag 29. Mai 2026, 08:41

Hallo zusammen,

ich bastle ("basteln" trifft es gut, da es mein erster Kontakt mit Python ist und ich mich an Videos und Anleitungen entlanghangle) an einem GUI für meine Musiksammlung.
Hierfür lese ich mit panda (read.excel) aus einer .xlsx Datei die gewünschten Daten aus und übergebe sie an ein ttk Label.
Das funktioniert inzwischen auch gut, aber die Darstellung gefällt mir nicht.

Zur Veranschaulichung:
Bild

Rechts oben im Label "Musik_gesamt_Ausgabe" kann ich die Formate ausrichten, dafür ist die Anzahl versetzt oder umgedreht.
Unten im Label "Album_label" passt der header im großen und ganzen. Die Spalte "Band" ist noch ausgerichtet aber danach wird es vogelwild.

Kann ich dieses Chaos irgendwie ordnen oder wäre es besser jede Zeile in ein eigenes Label zu überführen?


Ich versuche inzwischen vermutlich länger, dieses Chaos zu ordnen, als der Aufbau des restlichen GUI gedauert hat.

Code: Alles auswählen

....
d = pd.read_excel('Tonträger-Liste.xlsx',sheet_name='Tabelle1',header=0,names=['Band','Titel','Erscheinungsjahr','Format','Herkunft','Limitierug','Bemerkung','Band-korrigiert'])
d_format = d['Format'].value_counts(normalize=False, sort=True)
....
Musik_gesamt_Ausgabe = ttk.Label(root, text=str(d_format.to_string(header=True)), justify="left", font=("Arial", 15),borderwidth=2, relief="solid")
Musik_gesamt_Ausgabe.grid(row=1, column=2, padx=(20, 10), pady=(2, 2), columnspan=3, sticky="e")
....
Album_Input = tk.StringVar(root, value=FoundBand.to_string(header=True,index=False,justify="left", na_rep="---",col_space=15))
Album_label= ttk.Label(root, text=str(Album_Input.get()), justify='left', font=("Arial", 15),borderwidth=2, relief="solid")
Album_label.grid(row=5, column=0, padx=(20, 10), pady=(2, 2), columnspan=3, sticky="ew")
....

Schon mal vorab vielen Dank für die Hilfe.
kiaralle
User
Beiträge: 196
Registriert: Donnerstag 19. August 2021, 19:11

Schau mal hier rein. War auch mein Problem :-)

viewtopic.php?t=59039
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@MrCrowncoin
Deine Daten sind vermutlich mit Tabulatoren (\t) getrennt. Hierdurch kommt aus aufgrund der unterschiedlichen Textlängen zu den verschobenen Spalten. Man sollte also im ersten Schritt zeilenweise alle durch Tabs getrennten Werte per ``.split()`` trennen, dann spaltenweise die Maximalbreiten bestimmen und diese Breiten dann per String Formatting auf die einzelnen Zeilen anwenden.

Wenn du die Ursprungsdaten hier reinstellst, kann ich / wir dir gerne eine Funktion dafür schreiben.
Sirius3
User
Beiträge: 18411
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: dass man mit Leerzeichen Text rechtsbündig ausrichten kann, geht nur bei Schriftarten mit fester Zeichenbreite. Hier ist die Lösung das Grid-Layout von Tk zu benutzen.

Code: Alles auswählen

import tkinter as tk

CONTENT = [
    ("Format", ""),
    ("CD", "530"),
    ("Digi-CD", "314"),
    ("LP", "211"),
    ("EP", "43"),
    ("MC", "23"),
    ("CD-R", "3"),
]

def main():
    window = tk.Tk()
    totals = tk.Frame(window)
    for index, row in enumerate(CONTENT):
        tk.Label(totals, text=row[0], anchor=tk.W).grid(row=index, column=1, sticky=tk.EW)
        tk.Label(totals, text=row[1], anchor=tk.E).grid(row=index, column=2, sticky=tk.EW)
    totals.pack()
    window.mainloop()

if __name__ == "__main__":
    main()
Benutzeravatar
MrCrowncoin
User
Beiträge: 3
Registriert: Freitag 29. Mai 2026, 08:41

Vielen Dank für die Antworten.

@Sirius3. Das muss ich mir genauer anschauen und ausprobieren. Den Inhalt von CONTENT müsste ich flexibel gestalten. Zumindest die Anzahlen.

@kiaralle, den Beitrag hatte ich in der Vorabsuche sogar gesehen, aber nicht als meine Lösung angesehen. Ich schaue mir das mal näher an.

@snafu die Trennung durch die Tabulatoren müsste dann beim Einlesen der Excel passieren, oder?
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wie liest du die Excel Datei denn ein? Nutzt du Pandas dafür? Bei der Ausgabe kannst du dich durchaus an das Vorgehen von Sirius halten.
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

MrCrowncoin hat geschrieben: Sonntag 31. Mai 2026, 15:07 @Sirius3. Das muss ich mir genauer anschauen und ausprobieren. Den Inhalt von CONTENT müsste ich flexibel gestalten. Zumindest die Anzahlen.
Dafür kann man den Code ja anpassen:

Code: Alles auswählen

import tkinter as tk

CONTENT = [
    ("Format", ""),
    ("CD", "530"),
    ("Digi-CD", "314"),
    ("LP", "211"),
    ("EP", "43"),
    ("MC", "23"),
    ("CD-R", "3"),
]

def make_labels(content, master):
    for i, row in enumerate(content):
        for j, string in enumerate(row):
            tk.Label(
                master, text=string, anchor=tk.E if string.isdigit() else tk.W
            ).grid(row=i, column=j, sticky=tk.EW)
    master.pack()

def main():
    window = tk.Tk()
    totals = tk.Frame(window)
    make_labels(CONTENT, totals)
    window.mainloop()

if __name__ == "__main__":
    main()
Hinweis: isdigit() funktioniert nur mit reinen Ziffern ohne Vorzeichen. Negative Zahlen, Kommazahlen und andere Darstellungen erkennt er damit nicht als Zahl. Dafür müsste man sich eine eigene Funktion schreiben:

Code: Alles auswählen

def is_number(string):
    try:
        float(string)
    except ValueError:
        return False
    else:
        return True
Benutzeravatar
__blackjack__
User
Beiträge: 14402
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das `master.pack()` würde ich nicht mit in die Funktion stecken. Das ist nicht deren Aufgabe und ist überraschend für den Leser.
“The city's central computer told you? R2D2, you know better than to trust a strange computer!” — C3PO
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das ist tatsächlich etwas schräg. Anbei ein Beispiel, wo die Hilfsfunktion den Frame erstellt und füllt:

Code: Alles auswählen

import tkinter as tk

CONTENT = [
    ["Format"],
    ["CD", "530", "spam"],
    ["Digi-CD", "314", "ham"],
    ["LP", "211", "eggs"],
    ["EP", "43", "foo"],
    ["MC", "23", "bar"],
    ["CD-R", "3", "baz"],
]

def make_frame(master, rows):
    frame = tk.Frame(master)
    for i, row in enumerate(rows):
        for j, string in enumerate(row):
            tk.Label(
                frame, text=string, anchor=tk.E if string.isdigit() else tk.W
            ).grid(row=i, column=j, padx=5, sticky=tk.EW)
    return frame

def main():
    window = tk.Tk()
    make_frame(window, CONTENT).pack(side=tk.LEFT)
    window.mainloop()

if __name__ == "__main__":
    main()
Benutzeravatar
MrCrowncoin
User
Beiträge: 3
Registriert: Freitag 29. Mai 2026, 08:41

Hallo zusammen,

entschuldigt dass meine Antworten gerne etwas länger dauern. Ich habe leider weniger Zeit für die Bastelei, als ich gerne aufwenden würde.

@Kiaralle
Ich habe einen Moment gebraucht, bis ich verstanden habe, dass Text() mein bisheriges Label() ersetzt.
ABER das funktioniert! Vielen Dank dafür!
Ich muss noch etwas feinjustieren, aber grundsätzlich funktioniert es.

@Snafu & @Sirius3
Auch wenn die Variante von kiaralle aktuell für mich funktioniert, werde ich eure Variante trotzdem auch testen. Da muss ich mich aber definitiv mehr reindenken.
Da ich bei Python am Anfang stehe, bin ich aber froh über jeden Lösungsansatz.
Vielen Dank für eure Hilfe!
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

In dem Link wird es ja mit Tabs (\t) gezeigt. Genau das ist doch der Kern deines Problems. Du kannst es eben nicht mit einem einzelnen Tab zwischen den Spalten lösen, weil der Inhalt unterschiedlich lang ist. Das ist genau wie in Word und ähnlichen Programmen.

Wo genau liegt denn noch das Problem? Dass du einen DataFrame vorliegen hast, ergibt sich ja aus deinem eingangs gezeigten Code. Daher hier für Pandas angepasst:

Code: Alles auswählen

import tkinter as tk
import pandas as pd

CONTENT = pd.DataFrame([
    ["Format"],
    ["CD", "530", "spam"],
    ["Digi-CD", "314", "ham"],
    ["LP", "211", "eggs"],
    ["EP", "43", "foo"],
    ["MC", "23", "bar"],
    ["CD-R", "3", "baz"],
])

def make_frame(master, rows):
    frame = tk.Frame(master)
    for i, row in enumerate(rows):
        for j, string in enumerate(row):
            anchor = "e" if string and string.isdigit() else "w"
            tk.Label(
                frame, text=string, anchor=anchor
            ).grid(row=i, column=j, padx=5, sticky="ew")
    return frame

def make_window(rows):
    window = tk.Tk()
    make_frame(window, rows).pack(expand=True)
    window.mainloop()

def main():
    make_window(CONTENT.values)

if __name__ == "__main__":
    main()
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Man kann es halt naiv betrachten und einfach die to_string() Methode des DataFrames benutzen. Nur kommt es dann zu den bereits erwähnten Darstellungsfehlern. Der Trick mit den Leerzeichen klappt nur im Terminal oder anderen Programmen, wo eine feste Zeichenbreite genutzt wird. Das wurde ja bereits angesprochen und ist letztlich nicht zielführend. Außer du willst eine Darstellung in "Schreibmaschinen-Schrift" haben.
Benutzeravatar
grubenfox
User
Beiträge: 655
Registriert: Freitag 2. Dezember 2022, 15:49

snafu hat geschrieben: Mittwoch 3. Juni 2026, 15:29 In dem Link wird es ja mit Tabs (\t) gezeigt. Genau das ist doch der Kern deines Problems. Du kannst es eben nicht mit einem einzelnen Tab zwischen den Spalten lösen, weil der Inhalt unterschiedlich lang ist. Das ist genau wie in Word und ähnlichen Programmen.
Genau dafür sind Tabs doch da: um Texte an festen Spaltenpositionen auszurichten (linksbündig, rechtsbündig, ...), auch wenn die Texte unterschiedliche Längen haben.

Code: Alles auswählen

import tkinter as tk
import pandas as pd

CONTENT = pd.DataFrame([
    ["CD", "530", "spam"],
    ["Digi-CD", "314", "ham"],
    ["LP", "211", "eggs"],
    ["EP", "43", "foo"],
    ["MC", "23", "bar"],
    ["CD-R", "3", "baz"],
])

def make_tabframe(master, rows):
    tabframe = tk.Text(master, font=('arial', 12, 'italic'), border=0, wrap='word', bg="#eaecac", tabs=('3c', tk.RIGHT, '5c', tk.RIGHT))
    tabframe.config(fg="#000000", height=10 ,  width=99,  padx=5, pady=0)
    content = 'Format\n'
    for row in rows:
        line = None
        for string in row:
            if line is None:
                line = string
            else:
                line = f'{line}\t{string}'
        content = f'{content}\n{line}'
    tabframe.insert('0.0', f'{content}')
    return tabframe

def make_window(rows):
    window = tk.Tk()
    make_tabframe(window, rows).pack(expand=True)
    window.mainloop()

def main():
    make_window(CONTENT.values)

if __name__ == "__main__":
    main()
Unschön wird es wenn ein Text länger ist als der Platz zwischen zwei Tab-Positionen. Da ist die Variante mit 'Grid' die flexiblere...

_______________________________________________________________________________
https://www.python-kurs.eu/index.php
https://learnxinyminutes.com/docs/python/

https://quickref.me/python https://docs.python-guide.org/
https://www.youtube.com/watch?v=qU3Rc6_B9es
Benutzeravatar
snafu
User
Beiträge: 6979
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

grubenfox hat geschrieben: Mittwoch 3. Juni 2026, 17:53 Unschön wird es wenn ein Text länger ist als der Platz zwischen zwei Tab-Positionen. Da ist die Variante mit 'Grid' die flexiblere...
Genau darauf wollte ich hinaus. Und die Tabs passen streng genommen auch nur bei spezifischen Font-Einstellungen. Klar wird es im Normalfall häufig passen, aber es gibt eben auch Grenzfälle. Ich würde bei einer GUI-Anwendung jedenfalls nicht auf Tabs setzen.

Und anstelle deines Zusammenstückeln von Strings gibt es bekanntlich die join()-Methode.

Letztlich verbraucht deine Lösung mehr Zeilen bzw. mehr Code, ist weniger robust und IMHO schlechter nachvollziehbar als die Variante mit grid().
Antworten