Dynamische Textfeldgröße

Fragen zu Tkinter.
Antworten
Zizibee
User
Beiträge: 229
Registriert: Donnerstag 12. April 2007, 08:36

Hallo zusammen,

ich habe ein Fenster mit drei Textfeldern. Ein Eingabefeld namens text_field und zwei Ausgabetextfelder mit den Namen evaluation_output und sum_evaluation.
Wie alles angeordnet ist sieht man wohl am Besten direkt am Code.

Wenn ich das Fenster in der Größe änder, soll sich text_field dazu passend in der Höhe und der Breite ändern. evaluation_output ändert nur seine Höhe passen zum texf_field und soll am rechten Rand bleiben. sum_evaluation soll unten rechts bleiben und seine Größe beibehalten.

Ich habe das über ein Event gelöst, aber leider war das ein ziemliches Gefrickel, da die Fenstergröße wohl in Pixel und die Größe der Textfelder in Zeichen angegeben wird. Je nach Fenstergröße passt das jetzt mehr oder weniger gut.
Gibt es eine Methode das ordentlich zu machen?

Hier der Quellcode des Minimalbeispiels:

Code: Alles auswählen

import tkinter as tk

TEXTBOX_WIDTH = 30
EVALUATION_OUTPUT_WIDTH = 5
STANDARD_HEIGHT = 10

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.bind("<Configure>", self.adaption_to_frame_size)
        self.frame = tk.Frame(self.master)

        self.text_field = tk.Text(self.frame, height=STANDARD_HEIGHT, width=TEXTBOX_WIDTH)
        self.text_field.grid(row=0, column=0, sticky='nws')

        self.evaluation_output = tk.Text(self.frame, height=STANDARD_HEIGHT, width=EVALUATION_OUTPUT_WIDTH)
        self.evaluation_output.config(state='disabled')
        self.evaluation_output.grid(row=0, column=1, sticky='ne')

        self.sum_evaluation = tk.Text(self.frame, height=1, width=EVALUATION_OUTPUT_WIDTH)
        self.sum_evaluation.config(state='disabled')
        self.sum_evaluation.grid(row=1, column=1, sticky='se')

        self.frame.grid()


    def adaption_to_frame_size(self, event):
        frame_width = int(self.master.winfo_width())
        frame_height = int(self.master.winfo_height())
        self.text_field.config(width=int(frame_width/8.2)-EVALUATION_OUTPUT_WIDTH, height=frame_height//17)
        self.evaluation_output.config(width=EVALUATION_OUTPUT_WIDTH, height=frame_height//17)


def main():
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Schon einmal vielen Dank!
Zizibee
User
Beiträge: 229
Registriert: Donnerstag 12. April 2007, 08:36

Jetzt nach den Feiertagen will ich das Thema noch einmal hervorholen.
Hat hier niemand einen Vorschlag, eine Idee oder einen Tipp? Gibt es vielleicht etwas geschickteres als eine Textbox oder ist für so etwas schon tkinter der falsche Ansatz?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich muesste damit mehr rumspielen als ich gerade eruebrigen kann, aber du benutzt doch schon grid - damit kannst du doch mit sticky das eine Textfeld in alle Richtungen sich ausdehnen lassen, siehe zB https://stackoverflow.com/questions/759 ... in-tkinter
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Zizibee: Man muss und sollte sich da überhaupt nicht selbst drum kümmern. Die Anzeigeelemente müssen an allen Seiten ”kleben” und die Gewichte bei der Verteilung falls mehr Platz vorhanden ist, legt man für Zeilen/Spalten im Grid mit `rowconfigure()`/`columnconfigure()` fest.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Zizibee
User
Beiträge: 229
Registriert: Donnerstag 12. April 2007, 08:36

Danke schon einmal für eure Hilfe. Ich habe euren Input testweise mit Frames umgesetzt und das verhält sich wie gewünscht:

Code: Alles auswählen

import tkinter as tk

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("640x350")

        self.master.columnconfigure(0, weight=1000, min=40)
        self.master.columnconfigure(1, weight=1, min=40)
        self.master.rowconfigure(0, weight=1000, min=20)
        self.master.rowconfigure(1, weight=1, min=20)

        self.frame_left = tk.Frame(self.master, bg='green')
        self.frame_right_top = tk.Frame(self.master, bg='red')
        self.frame_right_bottom = tk.Frame(self.master, bg='yellow')

        self.frame_left.grid(row=0, column=0, sticky='WENS')
        self.frame_right_top.grid(row=0, column=1, sticky='WENS')
        self.frame_right_bottom.grid(row=1, column=1, sticky='WENS')
        self.master.grid()


def main():
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Wenn ich die tk.Frame jetzt aber durch tk.Text ersetze

Code: Alles auswählen

        self.frame_left = tk.Text(self.master)
        self.frame_right_top = tk.Text(self.master)
        self.frame_right_bottom = tk.Text(self.master)
sieht alles anders aus. Die Felder die groß sein sollen sind nun klein und umgekehrt.

Es scheint so, als wären jeweils die beiden Zeilen und die beiden Spalten vertauscht und wenn ich das von Hand anpasse, dann passt die Größenanpassung für größere Fenster nicht mehr, so als wenn ich für das Textfeld links eine maximale Größe vorgegeben hätte...

Verhält sich tk.Text wirklich so anders als tk.Frame?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kannst du nicht einfach den Text in einen Frame stecken? Und darum einfach allen Platz ausfüllen lassen? Solche konstrukte sind in GUIs durchaus notwendig.
Zizibee
User
Beiträge: 229
Registriert: Donnerstag 12. April 2007, 08:36

Wahrscheinlich stelle ich mich gerade etwas ungeschickt an, aber wenn ich die Textfelder in die Frames packe, habe ich das gleiche merkwürdige verhalten wie ganz ohne Frames...

Code: Alles auswählen

import tkinter as tk

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("640x350")
        self.master.columnconfigure(0, weight=1000, min=40)
        self.master.columnconfigure(1, weight=1, min=40)
        self.master.rowconfigure(0, weight=1000, min=20)
        self.master.rowconfigure(1, weight=1, min=20)

        self.frame_left = tk.Frame(self.master, bg='green')
        self.frame_right_top = tk.Frame(self.master, bg='red')
        self.frame_right_bottom = tk.Frame(self.master, bg='yellow')

        self.frame_left.columnconfigure(0, weight=1)
        self.frame_left.rowconfigure(0, weight=1)
        self.frame_right_top.columnconfigure(0, weight=1)
        self.frame_right_top.rowconfigure(0, weight=1)
        self.frame_right_bottom.columnconfigure(0, weight=1)
        self.frame_right_bottom.rowconfigure(0, weight=1)

        self.text_left = tk.Text(self.frame_left)
        self.text_right_top = tk.Text(self.frame_right_top)
        self.text_right_bottom = tk.Text(self.frame_right_bottom)

        self.frame_left.grid(row=0, column=0, sticky='WENS')
        self.frame_right_top.grid(row=0, column=1, sticky='WENS')
        self.frame_right_bottom.grid(row=1, column=1, sticky='WENS')

        self.text_left.grid(row=0, column=0, sticky='WENS')
        self.text_right_top.grid(row=0, column=0, sticky='WENS')
        self.text_right_bottom.grid(row=0, column=0, sticky='WENS')

        self.master.grid()


def main():
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Du musst den `Text`-Widgets eine grösse in Zeichen mitgeben, sonst werden offenbar recht grosse Defaultwerte genommen. Und das 1000 zu 1 ist Quatsch. Das sollte wohl eher 1 und 0 sein. 0 = wird nicht grösser. Bei 1000 zu 1 werden die dann doch irgendwann grösser nämlich für jede 1000 Pixel der andere Spalte/Zeile um 1 Pixel. Allerdings klappt das nicht so ganz. Jedenfalls nicht auf meinem Rechner. Mit so irrwitzigen Verhältnissen haben die Programmierer wohl nicht gerechnet. 🙂
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Zizibee
User
Beiträge: 229
Registriert: Donnerstag 12. April 2007, 08:36

@ __blackjack__: Vielen Dank für die Hilfe, auf das '0 = wird nicht größer' hätte ich auch mal selber kommen können :oops:
Zusammen mit der Startgröße der Textfelder funktioniert das jetzt wie gewollt :)

Hier mal "meine" Lösung:

Code: Alles auswählen

import tkinter as tk

class MainWindow:
    def __init__(self, master):
        self.master = master

        self.master.columnconfigure(0, weight=1, min=10)
        self.master.columnconfigure(1, weight=0, min=3)
        self.master.rowconfigure(0, weight=1)
        self.master.rowconfigure(1, weight=0)

        self.text_left = tk.Text(self.master)
        self.text_right_top = tk.Text(self.master)
        self.text_right_bottom = tk.Text(self.master)

        self.text_left.config(width=20, height=10)
        self.text_right_top.config(width=3, height=10)
        self.text_right_bottom.config(width=3, height=1)

        self.text_left.grid(row=0, column=0, sticky='WENS')
        self.text_right_top.grid(row=0, column=1, sticky='WENS')
        self.text_right_bottom.grid(row=1, column=1, sticky='WENS')
        self.master.grid()


def main():
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Antworten