Frage zu frames

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
StMan
User
Beiträge: 29
Registriert: Sonntag 11. Januar 2026, 17:48

Hallo,
wie kann ich erreichen dass die frames die ganze Fensterbreite nutzen und die Witgets darin zentriert werden?
Bei diesn Einstellungen nutzen sie nur ~4/5 der Breite, und die Witges sind alle linksseitig ausgerichtet. Egal was ich in sticky reinschreibe oder leer lasse.

Code: Alles auswählen

        root.rowconfigure(0, weight=1)  # oben
        root.rowconfigure(1, weight=1)  # mitte
        root.rowconfigure(2, weight=1)  # unten
        root.columnconfigure(0, weight=1)  
        root.columnconfigure(1, weight=1)  
        root.columnconfigure(2, weight=1)  
        
        
        frame_oben = tk.Frame(root, bg="lightblue")
        frame_oben.grid(row=0, column=0, sticky="nswe")
        #frame_oben.grid_propagate(True)
       
        frame_mitte = tk.Frame(root, bg="lightyellow")
        frame_mitte.grid(row=1, column=0, sticky="nswe")
        
        frame_unten = tk.Frame(root, bg="lightblue")
        frame_unten.grid(row=2, column=0, sticky="nswe")
Gruß Manfred
Benutzeravatar
snafu
User
Beiträge: 6936
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ist fast richtig. Wenn du columnconfigure() nur auf Spalte 0 anwendest, müsste es klappen:

Code: Alles auswählen

import tkinter as tk

COLORS = ["lightblue", "lightyellow", "lightblue"]

def main():
    root = tk.Tk()
    root.geometry("100x150")
    root.columnconfigure(0, weight=1)

    for i, color in enumerate(COLORS):
        root.rowconfigure(i, weight=1)
        frame = tk.Frame(root, bg=color)
        frame.grid(row=i, column=0, sticky="nswe")

    root.mainloop()


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

Und hier noch eine Variante ohne Angabe der Fenstermaße:

Code: Alles auswählen

import tkinter as tk

COLORS = ["lightblue", "lightyellow", "lightblue"]


def main():
    root = tk.Tk()
    root.columnconfigure(0, weight=1)
    row_indices = list(range(len(COLORS)))
    root.rowconfigure(row_indices, weight=1, minsize=50)
    
    for i, color in zip(row_indices, COLORS):
        frame = tk.Frame(root, bg=color)
        frame.grid(row=i, column=0, sticky="nswe")
    
    root.mainloop()


if __name__ == "__main__":
    main()
Pedroski55
User
Beiträge: 38
Registriert: Freitag 25. Juli 2025, 00:20

und die Witgets darin zentriert werden?
zentriert ist default

Spiele hiermit, man sehen welche Veränderungen was bewirken. Nicht zuviel auf einmal abändern!

Code: Alles auswählen

import tkinter as tk

# https://pythonguides.com/python-tkinter-grid/
# https://www.pythontutorial.net/tkinter/tkinter-grid/

def myApp():
    # mach Fenster
    win = tk.Tk(className='Streifen machen schlank')
    # geomancing
    win.geometry("400x400")    
    win['background']='pink'
    # mach a 3 x 2 grid
    win.columnconfigure(0, weight=1, minsize= 100)
    win.columnconfigure(1, weight=1, minsize= 100)
    win.columnconfigure(2, weight=1, minsize= 100)
    win.rowconfigure(0, weight=1, minsize= 30)
    win.rowconfigure(1, weight=2, minsize= 30)
    # mach labels
    colourr = 'red'
    colourg = 'green'
    coloury = 'yellow'
    label_one = tk.Label(win, text="One", bg=colourr, borderwidth=3, relief="sunken", width=5, height=2)
    label_two = tk.Label(win, text="Two", bg=coloury, borderwidth=4, relief="sunken", width=6, height=3)
    label_three = tk.Label(win, text="Three", bg=colourg, borderwidth=5, relief="sunken", width=7, height=4)
    label_four = tk.Label(win, text="Four", bg=colourr, borderwidth=3, relief="sunken", width=5, height=2)
    label_five = tk.Label(win, text="Five", bg=coloury, borderwidth=4, relief="sunken", width=6, height=3)
    label_six = tk.Label(win, text="Six", bg=colourg, borderwidth=5, relief="sunken", width=7, height=4)
    # labeln zum grid
    # default ist zentriert
    label_one.grid(row = 0, column = 0, ipadx = 5, ipady=5, padx = 5, pady=5)
    label_two.grid(row = 0, column = 1, ipadx = 5, ipady=5, padx = 2, pady=2)
    label_three.grid(row = 0, column = 2, ipadx = 5, ipady=5, padx = 5, pady=5)
    label_four.grid(row = 1, column = 0, ipadx = 5, ipady=5, padx = 2, pady=2)
    label_five.grid(row = 1, column = 1, ipadx = 5, ipady=5, padx = 5, pady=5)
    label_six.grid(row = 1, column = 2, ipadx = 5, ipady=5, padx = 2, pady=2)
    win.mainloop()
Benutzeravatar
StMan
User
Beiträge: 29
Registriert: Sonntag 11. Januar 2026, 17:48

OK, soweit alles gut.
Aber ich habe mein root mit frames auf zwei (oder drei ) Spalten aufgeteilt. Mein Problem ist dass die Zeilen von Spalte 0 die Zeilen der Spalte 1 beeinflussen.
Beispiel: in Spalte 0. Z0-tk.label, Z1- tk.Entry, Z2 tk.Entry, Z3 tk.Entry jeweils mit label davor. Z4-tk.label, z5-tk.label. Soweit alles gut!
Jetzt trage ich in Spalte 1. Z0-tk.label, Z1 eine Listbox, nun wird alles in Spalte 0 auseinander gezogen und verschoben..
Wie kann ich die Spalte 0 und 1 voneinander unabhängig machen? Oder habe ich da ein Denkfehler.
Gruß Manfred
Benutzeravatar
snafu
User
Beiträge: 6936
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@StMan: Zeig mal bitte tatsächlichen Code, der das Problem verdeutlicht.
Benutzeravatar
StMan
User
Beiträge: 29
Registriert: Sonntag 11. Januar 2026, 17:48

es geht erstmal nur frame_oben_re, frame_oben_mi und frame_oben_re. Mit .rowconfigure und columnconfigure habe ich schon alles ausprobiert.

Code: Alles auswählen

#region main-Window
class mainWindow:
    def __init__(self, root, app, status_var):
        self.root = root
        self.app = app
        self.status_var = status_var 
    
        SCREEN_WIDTH = root.winfo_screenwidth()
        SCREEN_HEIGTH = root.winfo_screenheight()
        WIN_WIDTH = 700
        WIN_HEIGTH = 800
        WIN_X = (SCREEN_WIDTH - WIN_WIDTH) // 2
        WIN_Y = (SCREEN_HEIGTH - WIN_HEIGTH) // 2        
        root.title("Das Hauptfenster")
        root.geometry(f"{WIN_WIDTH}x{WIN_HEIGTH}+{WIN_X}+{WIN_Y}")
        root.attributes("-topmost",True)
        root.option_add("*font","ARIAL 12")
        root.configure(bg="#b5b3b3")
        root.iconbitmap("C:/_Py-Dev/Bilder/mysql2.ico")
        
        pad = {"padx": 110, "pady": 10} 
        
        # Konfiguriere das grid-Layout 
        root.rowconfigure(0, weight=0)  # oben
        root.rowconfigure(1, weight=0)  # mitte
        root.rowconfigure(2, weight=0)  # unten
        root.columnconfigure(0, weight=0)  #Zeile 0 spannt sich über volle Breite, weight=0 nimmt keinen zusätzlichen Platz ein
        root.columnconfigure(1, weight=1)  #Zeile 1 spannt sich über volle Breite
        root.columnconfigure(2, weight=0)  #Zeile 2 spannt sich über volle Breite
        
        
        frame_oben_li = tk.Frame(root, bg="lightblue")
        frame_oben_li.grid(row=0, column=0, sticky="nswe")
        #frame_oben.grid_propagate(True)
        
        frame_oben_mi = tk.Frame(root, bg="#ffbad9")
        frame_oben_mi.grid(row=0, column=1, sticky="nswe")
        #frame_oben.grid_propagate(True)
        
        frame_oben_re = tk.Frame(root, bg="lightgreen")
        frame_oben_re.grid(row=0, column=2, sticky="nswe")
       
        frame_mitte = tk.Frame(root, bg="lightyellow")
        frame_mitte.grid(row=1, column=0, columnspan=3,sticky="nswe")
        
        frame_unten = tk.Frame(root, bg="lightblue")
        frame_unten.grid(row=2, column=0, columnspan=3, sticky="nswe")
        
        
        # Überschrift
        lb_ueberschrift = ttk.Label(frame_oben_li, background="#4ec9b0" , font= "Arial 9",  text="Bitte Daten zur Anmeldung bei mySQL eingeben")
        lb_ueberschrift.grid(column=0, row=0, padx=0, pady=10,  sticky="")
        
        ########## Überschrift label oben links ###############
        lb_mitte = ttk.Label(frame_oben_re, font= "Arial 8", text="Datenbank mit Doppelklick wählen")
        lb_mitte.grid(column=1, row=1, padx=0, pady=10, sticky="")
        
        # Host
        ttk.Label(frame_oben_li, text="Host:").grid(column=0, row=1, sticky="sw",pady=10, padx=60)
        self.host_var = tk.StringVar(value="localhost")
        ttk.Entry(frame_oben_li, textvariable=self.host_var, width=20).grid(column=0, row=1, sticky="",**pad)

        # Username
        ttk.Label(frame_oben_li, text="Username:").grid(column=0, row=2, sticky="w", pady=60, padx=20)
        self.user_var = tk.StringVar(value="root")
        ttk.Entry(frame_oben_li, textvariable=self.user_var, width=20).grid(column=0, row=2, sticky="",**pad)

        # Password
        ttk.Label(frame_oben_li, text="Password:").grid(column=0, row=3, sticky="w", pady=10,padx=22)
        self.password_var = tk.StringVar()
        ttk.Entry(frame_oben_li, textvariable=self.password_var, show="*", width=20).grid(column=0, row=3, sticky="",**pad)

        host = self.host_var.get().strip()
        username = self.user_var.get().strip()
        password = self.password_var.get()
        
        # Buttons
        ttk.Button(frame_oben_li, text="Connect", command=self.on_connect).grid(column=0, row=5, padx=(100,0), sticky="")
        ttk.Button(frame_oben_li, text="Quit", command=root.destroy).grid(column=0, row=5, padx=(0,100), sticky="")
        
        ###########    Status Label    #########
        # Status label
        self.status_label = ttk.Label(frame_mitte, text="warte auf verbindung", foreground="#9f0263", font="ARIAL 10 bold",anchor="w") 
        self.status_label.grid(column=0, row=0, sticky="", pady=10) #, padx=120)              

      
        
        #########   Datenbank Listbox  ########### 
        self.var_all = tk.BooleanVar()
        self.checkbox_all = tk.Checkbutton(frame_oben_re, text="Auch Systemdatenbanken anzeigen", font="ARIAL 8",variable=self.var_all,) #command=update_list)
        self.checkbox_all.grid(row=2, column=1, ipadx=0, ipady=0,sticky="NW",padx=(50,0), pady=0)
        
        self.dbOrdner_inhalt= []
        
        self.dbOrdner_scrollbar = tk.Scrollbar(frame_oben_re, orient="vertical") 
        self.dbOrdner_scrollbar.grid(row=3, column=1, ipady=32, sticky="NW")  #, padx=(290,0), pady=32)  
        
        self.dbOrdner_listbox = tk.Listbox(frame_oben_re, height=6) 
        self.dbOrdner_listbox.grid(row=3, column=1, ipadx=30, sticky="NW")#,padx=(50,0), pady=(30,0))
        
        self.bOrdner_var = tk.Variable(frame_mitte, value=self.dbOrdner_inhalt) 
        self.dbOrdner_scrollbar.config(command=self.dbOrdner_listbox.yview)
        for item in self.dbOrdner_inhalt: self.dbOrdner_listbox.insert("end", item)
        #self.dbOrdner_listbox.bind("<Double-1>",lambda e: print(self.dbOrdner_listbox.get(self.dbOrdner_listbox.curselection())))
            
        self.selected_value = None
        self.dbOrdner_listbox.bind("<Double-1>", lambda e: self.fetch_table_from_selection())
                        
        ########### neue Datenbank anlegen  ##########################
        db_btn=ttk.Button(frame_oben_re, text="neue Datenbank anlegen", command=lambda:self.app.dbneu(host, username, password,self.dbname_var.get(),status_callback=self.update_status))
        db_btn.grid(column=1, row=1,sticky="n",padx=80, pady=30)
        self.dbname_var = tk.StringVar()
        ttk.Entry(frame_oben_re,textvariable=self.dbname_var, width=20).grid(column=1, row=1,sticky="n", padx=0,pady=70)
        dbname = self.dbname_var.get().strip()   
        

Gruß Manfred
Benutzeravatar
snafu
User
Beiträge: 6936
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich bin (im Moment) hier raus, da ich leider nicht verstehe, was dein Ziel ist...
Benutzeravatar
StMan
User
Beiträge: 29
Registriert: Sonntag 11. Januar 2026, 17:48

ich versuche es mal hiermit:
mein Fenster (root) aufgeteilt in 4 Bereiche.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xZ0 -----(Sp0- fr_oben_li)--------x------------(Sp0- fr_oben_lre)------------x
xZ1 label--------------------------------x--------------label-------------------------------x
xZ2 label + entry--------------------x-------#################--------x Bereich 1 +2
xZ3 label + entry--------------------x-------#--------listbox--------------#---------x
xZ4 label + entry--------------------x-------#--------------------------------#---------x
xZ5 label--------------------------------x--------################---------x
xxx#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xZ0------------------------------ Sp0--fr_mitte--------------------------------------------x
x
x-----------------------Bereich 3
x
xZ0----------------------------Sp0--fr_unten----------------------------------------------x
x
x----------------------Bereich4
x
x----------------------------------------------------------------------------------------------------x
Gruß Manfred
Benutzeravatar
StMan
User
Beiträge: 29
Registriert: Sonntag 11. Januar 2026, 17:48

Fehler:
nicht: xZ0 -----(Sp0- fr_oben_li)--------x------------(Sp0- fr_oben_lre)------------x
sonder: xZ0 -----(Sp0- fr_oben_li)--------x------------(Sp1- fr_oben_lre)------------x
mehr als 1 leerzeichen kann der Editor scheinbar nicht.
Gruß Manfred
Benutzeravatar
__blackjack__
User
Beiträge: 14306
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@StMan: Falls das irgendwie ausgerichtet sein sollte, dann darf das nicht einfach so als Text in den Beitrag, denn mehrere „whitespace“-Zeichen im HTML-Quelltext werden vom Browser in normalem Text zu einem Leerzeichen. Dazu zählen neben normalen Leerzeichen und Tabulatoren auch Zeilenenden. Weshalb das Forum netterweise schon mal Zeilenenden aus dem Editor nicht als normale Zeilenenden interpretiert, sondern dafür im HTML <br>-Tags einbaut. (Was blöd ist, weil man dadurch gezwungen ist für einen neuen Absatz Zeilenumbrüche zu schreiben und im Beitrag hinterher gar keine Absätze gesetzt sind, sondern semantisch alles in einem einzigen Absatz mit manuellen Zeilenumbrüchen + Leerzeilen steht.)

Wenn Einrückung und Leerzeichen in der Anzeige erhalten bleiben sollen (im Quelltext der Seite sind sie), dann muss man das in code-Tags setzen. Entweder manuell die Tags in den Beitrag schreiben, oder im vollständigen Editor den </>-Button benutzen im die einzufügen.

Dann bleibt noch das Problem, dass Du das offenbar auch im Editor im Forum eingegeben hast, mit einer Schriftart wo die einzelnen Buchstaben nicht gleich breit sind. Das mag bei Dir mit der Schriftart bei Dir halbwegs ordentlich ausgesehen haben, so dass die x an der rechten Seite (fast) untereinander stehen. Das ist aber bei anderen nicht der Fall, weil die andere Schriftarten verwenden können. Das Forum schlägt "Roboto", Arial, Helvetica, und sans-serif vor. Das heisst das wird bei den Lesern in Roboto, Arial, Helvetica, angezeigt, oder einer Schrift die für diese als Ersatz beim Leser eingestellt ist, oder irgend einer anderen serifenlosen Schrift. Selbst auf serifenlos kann man sich nicht verlassen wenn das beispielsweise in einem textbasierten Browser im Terminal angezeigt wird, oder der Benutzer als serifenlose Schrift eine mit Serifen eingestellt hat.

Wenn das für alle lesbar sein soll, müsstest Du diese Text-Grafik in einem Editor schreiben wo eine Schriftart eingestellt ist, bei der alle Zeichen gleich breit sind, und das dann hier im Forum in den Editor zwischen code-Tags setzen. Halt wie Quelltext.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Benutzeravatar
snafu
User
Beiträge: 6936
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@StMan:
Dir geht es also darum, dass die Listbox im rechten Bereich aufgrund ihrer Höhe durch die Einträge den linken Frame mit nach unten zieht, richtig? Von wie vielen Einträgen sprechen wir denn? Steht die Anzahl fest oder kann die wachsen? Gut möglich, dass hier der Einsatz von einer vertikalen Scrollbar (also rechts von der Box) sinnvoll ist, um die Höhe der Box besser kontrollieren zu können.

Ist es denn okay, wenn die Listbox tiefer als Zeile 5 nach unten ragt? Möchtest du quasi, dass die Zeilen 0-5 für den linken Frame immer gleich hoch bleiben, aber rechts darf der Frame nach unten hin größer werden? Ich denke jedenfalls, du wirst für den grid()-Aufruf zum Anordnen der Listbox die rowspan-Option mitgeben müssen, sofern du das noch nicht getan hast.
Benutzeravatar
StMan
User
Beiträge: 29
Registriert: Sonntag 11. Januar 2026, 17:48

Bereich 1 + 2 also oben_li und oben_re sind gleich hoch und sollen auch so bleiben. Die Listbox hat eine Scrollbar.
mein Problem:
Ich erstelle zuerst den linken Bereich (frame_oben_li). Soweit alles gut.
Wenn ich nun den rechten Bereich (frame_oben_re) estelle, und die Listbox einfüge, werden die Abstände auf der linken Seite durcheinander gewürfelt.
Gruß Manfred
Benutzeravatar
snafu
User
Beiträge: 6936
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hast du es denn schon mit dem erwähnten rowspan probiert? Wie immer wäre konkreter Code hilfreich. Quasi ein Minimalbeispiel, wie du links und rechts mit den enthaltenen Widgets erstellst. Du kannst gerne Phantasietexte in den Code einbauen, aber die tatsächliche Anordnung und der Code zum Erstellen und Positionieren der Widgets sollte schon vorhanden sein, um dir konkreter helfen zu können.
Benutzeravatar
snafu
User
Beiträge: 6936
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich habe mal die KI angeschmissen. Das hier kam nach einer Folge von 5-6 Prompts raus:

Code: Alles auswählen

import tkinter as tk

class FormularBereich(tk.Frame):
    """Linke Seite: Enthält die Beschriftungen und Eingabefelder."""
    def __init__(self, parent):
        super().__init__(parent)
        
        labels = ["Vorname:", "Nachname:", "E-Mail:", "Telefon:", "Stadt:"]
        self.entries = {}

        for i, text in enumerate(labels):
            lbl = tk.Label(self, text=text)
            lbl.grid(row=i, column=0, sticky="e", padx=(0, 5), pady=2)
            
            entry = tk.Entry(self, width=20)
            entry.grid(row=i, column=1, sticky="w", pady=2)
            # Speichern der Entries in einem Dictionary für späteren Zugriff
            self.entries[text] = entry

class ListenBereich(tk.Frame):
    """Rechte Seite: Enthält das Label, die Listbox und die Scrollbar."""
    def __init__(self, parent):
        super().__init__(parent)
        
        # Grid-Konfiguration für die Listbox-Ausdehnung
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        tk.Label(self, text="Verfügbare Einträge:").grid(row=0, column=0, sticky="nw")

        self.listbox = tk.Listbox(self, height=6)
        self.listbox.grid(row=1, column=0, sticky="nsew")

        self.scrollbar = tk.Scrollbar(self, orient="vertical", command=self.listbox.yview)
        self.scrollbar.grid(row=1, column=1, sticky="ns")

        self.listbox.config(yscrollcommand=self.scrollbar.set)
        
        # Testdaten
        for i in range(20):
            self.listbox.insert("end", f"Eintrag {i+1}")

class StatusBereich(tk.Frame):
    """Unterer Bereich: Ein farbiger Platzhalter-Frame."""
    def __init__(self, parent, farbe="lightgreen"):
        super().__init__(parent, bg=farbe)
        # Hier könnten später Status-Labels oder Buttons ergänzt werden

class HauptAnwendung(tk.Tk):
    """Das Hauptfenster, das alle Komponenten zusammenführt."""
    def __init__(self):
        super().__init__()
        self.title("Strukturierte Tkinter Anwendung")
        
        # Layout-Gewichtung für das Hauptfenster
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        # 1. Oberer Container für Formular und Liste
        top_container = tk.Frame(self)
        top_container.grid(row=0, column=0, sticky="ew", padx=20, pady=20)
        top_container.columnconfigure(1, weight=1) # Nur die rechte Spalte (Liste) wächst

        # Instanziierung der Teilbereiche
        self.formular = FormularBereich(top_container)
        self.formular.grid(row=0, column=0, sticky="nw")

        self.liste = ListenBereich(top_container)
        self.liste.grid(row=0, column=1, sticky="nsew", padx=(40, 0))

        # 2. Unterer Bereich
        self.status = StatusBereich(self)
        self.status.grid(row=1, column=0, sticky="nsew")

        # Mindestgröße basierend auf dem Inhalt festlegen
        self.update()
        self.minsize(self.winfo_width(), self.winfo_height())

if __name__ == "__main__":
    app = HauptAnwendung()
    app.mainloop()
Geht das in etwa in die Richtung, die du dir vorgestellt hast?

Ich kann dir hier Google im KI-Modus empfehlen. In Tkinter scheint der recht gut zu sein. Die Benennung der Klassen kann man ihn ja noch vornehmen lassen oder das eben selbst ändern. PEP 8 sollte er auch können, wenn man ihm das sagt. Ich würde mir einen abbrechen, wenn ich beim Design das alles selber machen müsste. Ich finde Layouts programmieren in Tkinter nicht so prickelnd, dann lieber mit Qt.
Antworten