Beispiele für komplexere Tk GUIs ?!?

Fragen zu Tkinter.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Auf der suche nach Beispielen für eine komplexer Tkinter GUI, die grid und Frames nutzt, bin ich auf https://www.mikrocontroller.net/topic/277670 gestoßen...

Hab mir die letzte Version mal angesehen.

Die Interessanteste Datei darin ist net_io_main.py

Auf dessen Grundlage hab ich mal schnell das folgende zusammen gehackt:

Code: Alles auswählen

import tkinter as tk


class Outputs(tk.LabelFrame):
    def __init__(self, master, **kwargs):
        tk.LabelFrame.__init__(self, master, text="LCD-Ausgabe")
        self.grid(**kwargs)

        self._lbl = tk.Label(self, text="Foo", anchor="e")
        self._lbl.grid(column=0, row=0, sticky="e")

        self._var = tk.StringVar()
        self._entry = tk.Entry(self, textvariable=self._var)
        self._entry.grid(column=1, row=0, sticky="nse")

        self._btn = tk.Button(self, text="Zeile löschen")
        self._btn.grid(column=3, row=0, sticky="nse")


class Inputs(tk.LabelFrame):
    def __init__(self, master, **kwargs):
        tk.LabelFrame.__init__(self, master, text="Eingabe")
        self.grid(**kwargs)

        self._lbl = tk.Label(self, text="Foo", anchor="e")
        self._lbl.grid(column=0, row=0, sticky="e")

        self._var = tk.StringVar()
        self._entry = tk.Entry(self, textvariable=self._var)
        self._entry.grid(column=1, row=0, sticky="nse")

        self._btn = tk.Button(self, text="Zeile löschen")
        self._btn.grid(column=3, row=0, sticky="nse")


class Buttons(tk.LabelFrame):
    def __init__(self, master, **kwargs):
        tk.LabelFrame.__init__(self, master, text="Ein paar Buttons")
        self.grid(**kwargs)

        for no, txt in enumerate(["bla blub", "foo bar"]):
            self._btn = tk.Button(self, text=txt)
            self._btn.grid(column=no, row=0, sticky="nse")

        for no, txt in enumerate(["noch einer", "ende"]):
            self._btn = tk.Button(self, text=txt)
            self._btn.grid(column=no, row=1, sticky="nse")


class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Foo Bar")

        self.add_Widgets()

        self.mainloop()

    def add_Widgets(self):
        padding = 5
        defaults = {
            "ipadx": padding, # add internal padding in x direction
            "ipady": padding, # add internal padding in y direction
            "padx": padding, # add padding in x direction
            "pady": padding, # add padding in y direction
            "sticky": tk.NSEW, # stick to the cell boundary
        }

        self.outputs = Outputs(self, column=0, row=0, **defaults)
        self.inputs = Inputs(self, column=0, row=1, **defaults)
        self.actions = Buttons(self, column=1, row=0, rowspan=2, **defaults)


if __name__ == '__main__':
    App()

Ich finde diese Aufteilung eigentlich ganz nett. Wie sieht ihr das? Brauchbar, vom Prinzip her?!?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jens hat geschrieben:Ich finde diese Aufteilung eigentlich ganz nett. Wie sieht ihr das? Brauchbar, vom Prinzip her?!?
Also, recht nett, kann man es finden. Aber sehr komplex sicherlich nicht. Ich würde gerne etwas zeigen, und zwar ein GIF Bildchen. Mit Img kann man eine Bild URL eingeben. Nützt mir aber nichts. Im Persönlichen Bereich hatte ich Dateianhänge verwalten gefunden. Aber hochladen hatte ich nicht gefunden. Gibt es das irgendwo?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Nutzte irgendeinen Bilder paste Dienst....

Was mir noch einfällt: eine Art django-forms fehlt mir.
Kennt jemand sowas für tkinter?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Hab mal den Aufbau meines GUI Designers aufgelistet. Das könnte man wohl eine komplexe GUI nennen.

Code: Alles auswählen

Oberste Ebene hat Grid Layout:

- CreateFrame (Frame)
- CreateAndLayout (Frame)
- ConfigOptions (LabelFrame)
- DetailedLayout (Frame)
- Selection (LabelFrame)


- CreateFrame (Frame): Inhalt (LabelFrames) hat Pack Layout:

- CreateFrame - CreateWidget (LabelFrame): Inhalt hat Grid Layout
- CreateFrame - SelectType (LabelFrame): Inhalt hat Grid Layout

- CreateAndLayout (Frame) hat Pack Layout:

- CreateAndLayout - Options (LabelFrame): Inhalt hat Grid Layout
- CreateAndLayout - LayoutShort (Frame): Inhalt nur ein Element LayoutShortShowHide (LabelFrame) mit Grid 0,0
- CreateAndLayout - LayoutShort - LayoutShortShowHide (LabelFrame): Inhalt LabelFrames in Grid Layout
- CreateAndLayout - LayoutShort - LayoutShortShowHide - PackLayout (LabelFrame): Inhalt hat Pack Layout
- CreateAndLayout - LayoutShort - LayoutShortShowHide - GridLayout (LabelFrame): Inhalt hat Grid Layout
- CreateAndLayout - LayoutShort - LayoutShortShowHide - PlaceLayout (LabelFrame): Inhalt hat Grid Layout

- ConfigOptions (LabelFrame): Inhalt hat Pack Layout
- ConfigOptions - Scrollbar
- ConfigOptions - Canvas
- ConfigOptions - Frame: Der Frame als Window im Canvas mit Scrollbar für vertikal scrollen. Der Frame enthält dynamisch erzeugte Frames im Pack Layout. Für jede config option einen Frame
- ConfigOptions - Frame - Frame (Pack Layout): Dynamisch erzeugte Frames. Inhalt mit Grid Layout

- DetailedLayout (Frame): Inhalt nur ein einziger LabelFrame (Pack Layout)
- DetailedLayout - LayoutOptions (LabelFrame): Der LabelFrame enthält dynamisch erzeugte Frames im Pack Layout. Für jede Layout option einen Frame
- DetailedLayout - LayoutOptions - Frame: Dynamisch erzeugte Frames. Inhalt mit Grid Layout

- Selection (LabelFrame): Inhalt in Pack Layout
- Selection - Buttons (Frame): Inhalt in Pack Layout
- Selection - Buttons - Buttons1 (Frame): Inhalt diverse Buttons mit Pack Layout 
- Selection - Buttons - Buttons2 (Frame): Inhalt diverse Buttons mit Pack Layout 
- Selection - Buttons - LoadFrame (LabelFrame): GUI Load Eingabemaske mit Grid Layout für Laden mit Programmausführung
- Selection - Buttons - LoadEdit (LabelFrame): GUI Load Eingabemaske mit Grid Layout für Laden mit GUI Aufbau aber ohne Programmausführung
- Selection - Buttons - SaveFrame (LabelFrame): GUI Save Eingabemaske mit Grid Layout zum Speichern der GUI
- Selection - Buttons - RenameFrame (LabelFrame): Eingabemaske zum Umbenennen eines GUI Elements
- Selection - SelectionShow (Frame): Inhalt Grid Layout - dynamisch erzeugte Buttons zum Navigieren durch die GUI. Auswahl der Elemente im Container, des Containers, zurück aus dem Container wechseln in Untercontainer


außerdem
- ToplevelCodeEdit (TopLevel): temporär durch Buttondruck erzeugtes TopLevel Window zum editieren, testen, ausführen und übernehmen von Code. Inhalt Pack Layout
- ToplevelCodeEdit - Text (Text): Text Feld mit Code - Anzeige und Editieren
- ToplevelCodeEdit - Frame (Frame): Inhalt Bedienbuttons und Anzeige Labels mit Pack Layout (horizontal)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

On nun wenig komplex oder mehr... Mir geht es darum, wie eine gut skalierbare Art des GUI zusammenbaus aussehen sollte.

Im Netz findet man halt zu 90% einfachst Beispiele und/oder *-Import Beispiele... :?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
sparrow
User
Beiträge: 4144
Registriert: Freitag 17. April 2009, 10:28

@jens: ich finde die Art wie du das generierst sehr übersichtlich.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jens hat geschrieben:On nun wenig komplex oder mehr... Mir geht es darum, wie eine gut skalierbare Art des GUI zusammenbaus aussehen sollte.

Im Netz findet man halt zu 90% einfachst Beispiele und/oder *-Import Beispiele... :?
Eigentlich völlig egal, wie die GUI zusammengebaut ist, wenn die GUI Teile völlig unabhängig vom GUI Zusammenbau sind und stehen können, wo sie wollen. Das erreicht man mittels Kommunikation der GUI Teile miteinander durch Messages. Wenn etwa der User ein Place Layout gewählt hat und für sein Widget den Mouse Move eingeschaltet hat, dann kann er sein Widget in seiner Anwendung mit der Maus bewegen.

Wenn er sein Widget bewegt, werden die x und y Koordinaten angezeigt in:

- CreateAndLayout - LayoutShort - LayoutShortShowHide - PlaceLayout - X (Spinbox)
- CreateAndLayout - LayoutShort - LayoutShortShowHide - PlaceLayout - Y (Spinbox)

- DetailedLayout - LayoutOptions - Frame (für place info x) - Entry (Entry)
- DetailedLayout - LayoutOptions - Frame (für place info y) - Entry (Entry)

Alles kein Problem mit Messages

Dazu braucht es nur zwei Messages:

Code: Alles auswählen

def on_mouse_move(me,event):
	xpos = int(me.getlayout("x"))+event.x-me.mydata[0]
	ypos = int(me.getlayout("y"))+event.y-me.mydata[1]
	yxplace(ypos,xpos)
	send('POSITION_CHANGED')
	send('LAYOUT_VALUES_REFRESH')
Hier wird durch yxplace das widget bewegt. PlaceLayout wird durch die Message POSITION_CHANGED informiert und LayoutOptions durch die Message LAYOUT_VALUES_REFRESH
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: soll ich Deine Posts jetzt als SPAM auffassen? Du willst hier unbedingt Deinen Tk-Aufsatz bewerben, der noch nicht existiert? Wenn Du das willst, kannst Du das gerne in einem eigenen Thread unter ShowCase machen, aber nicht anderer Leute Threads zumüllen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: soll ich Deine Posts jetzt als SPAM auffassen? Du willst hier unbedingt Deinen Tk-Aufsatz bewerben, der noch nicht existiert? Wenn Du das willst, kannst Du das gerne in einem eigenen Thread unter ShowCase machen, aber nicht anderer Leute Threads zumüllen.
Sorry, es ging hier um komplexe GUIs und wie man beliebig komplexe GUIs implementieren kann, indem man für Unabhängigkeit der GUI Teile durch Messages sorgt. Wenn Du allerdings meinst, dass das nichts mit komplexen GUIs zu tun hat und es als zumüllen auffasst, dann halte ich mich da eben raus und schreib erst wieder etwas, wenn ich den GUI Designer veröffentlich habe und ihn dann vorstelle. Bzw. wenn es um das Datenformat geht, werde ich dazu unter einem eigenen Thread fragen, wie Ihr das gerne hättet. OK so?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

sparrow hat geschrieben:@jens: ich finde die Art wie du das generierst sehr übersichtlich.
Dann gehe ich mal davon aus, das es schon nah an "best practise" ran kommt?

Irgendwie fehlt mir da ein Artikel/Blog Post oder ähnliches drüber... Vermutlich weil Tk nur ein Schattendasein fristet?!? Von wegen, für was richtiges nimmt man Qt?!?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
sparrow
User
Beiträge: 4144
Registriert: Freitag 17. April 2009, 10:28

Ich habe mit Tk noch nie großartig was gemacht, daher könntest du recht haben ;)

Allerdings ist das definieren der GUI im Quelltext selten wirklich hübsch. Egal ob Tk, Qt oder Javas Swing.
Allerdings habe ich recht schnell verstanden was dein Quelltext macht, ohne viel Erfahrung mit Tk zu haben. Das ist für mich wesentlich und daher finde ich das für "ich definiere hier meine GUI" schon ziemlich gut.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

sparrow hat geschrieben:Allerdings ist das definieren der GUI im Quelltext selten wirklich hübsch. Egal ob Tk, Qt oder Javas Swing.
Ja, das sieht immer etwas Umständlich aus.

Das fängt schon bei ganz einfachen Dingen, wie dem Aufteilen per grid auf. Da must man ja mit row/column hantieren. Generell finde ich diese Art "Hardcoded" index Werte ziemlich blöd.

Dann, kann man theoretisch die gesamte GUI-App in einer Klasse in __init__ definieren. Aber das wird dann schnell recht unübersichtlich.

Deswegen die Idee, es nach logischen Blöcken zu unterteilen, die man dann zusammenpuzzelt...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jens hat geschrieben:
sparrow hat geschrieben:Allerdings ist das definieren der GUI im Quelltext selten wirklich hübsch. Egal ob Tk, Qt oder Javas Swing.
Ja, das sieht immer etwas Umständlich aus.

Das fängt schon bei ganz einfachen Dingen, wie dem Aufteilen per grid auf. Da must man ja mit row/column hantieren. Generell finde ich diese Art "Hardcoded" index Werte ziemlich blöd.

Dann, kann man theoretisch die gesamte GUI-App in einer Klasse in __init__ definieren. Aber das wird dann schnell recht unübersichtlich.

Deswegen die Idee, es nach logischen Blöcken zu unterteilen, die man dann zusammenpuzzelt...
Nach logischen Blöcken sollte man es sowieso ordnen. Allerdings wenn man eine komplexe GUI in die init reintut, kann es ganz schön unübersichtlich werden, etwa bei einer GUI mit 3000 Zeilen. Zum Editieren sind 20 Scripte in einem Unterverzeichnis wohl besser. Aber wenn man das Programm dann ausliefert, macht sich ein Vielzahl verschiedener Scripte auch nicht gut. Für den Anwender vielleicht besser, wenn man es zum Schluss doch zu einem File zusammenfügt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Alfons Mittelmeyer hat geschrieben:Aber wenn man das Programm dann ausliefert, macht sich ein Vielzahl verschiedener Scripte auch nicht gut. Für den Anwender vielleicht besser, wenn man es zum Schluss doch zu einem File zusammenfügt.
:shock:

Wo ist denn da das Problem?!?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jens hat geschrieben:
Alfons Mittelmeyer hat geschrieben:Aber wenn man das Programm dann ausliefert, macht sich ein Vielzahl verschiedener Scripte auch nicht gut. Für den Anwender vielleicht besser, wenn man es zum Schluss doch zu einem File zusammenfügt.
:shock:

Wo ist denn da das Problem?!?
Bin mir nicht sicher, was dem Anwender besser gefällt - ein Programm oder ein Verzeichnis mit vielen Teilen. Wenn er es nur benutzen, also aufrufen will - dann gefällt ihm ein Programm eventuell besser. Wenn er aber etwas ändern will, wären kleinere übersichtliche Teile, die nur eine Sache behandeln, besser.

Eigentlich egal, muss nur noch eine Funktion schreiben, welche die Markierungen für zugeladene Teile rausnimmt. Dann kann man das auch als ein einziges Programm speichern.
Zuletzt geändert von Alfons Mittelmeyer am Montag 24. August 2015, 13:36, insgesamt 2-mal geändert.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: was meinst Du jetzt schon wieder mit Scripte? Ein größeres Programm wird zwangsläufig aus vielen Modulen bestehen, aber das ist ja auch kein Problem, das stört den Anwender ja auch nicht.

@jens: es ist auf jeden Fall sinnvoll, logisch zusammengehörende Einheiten in einzelne Frames zu packen, um sowohl logisch, als auch im Fenster eine Hirachie aufzubauen. Was mich an Deinem Beispiel etwas stört ist, dass sich die LabelFrames selbst platzieren. Das ist eigentlich die Aufgabe der höheren Instanz. Bei Label oder Button rufst Du ja auch danach die grid-Methode auf.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

@Alfons Mittelmeyer: Dieses "eine Datei == Programm/App" funktioniert ja eh nur bei überschaubaren Dingen. Also quasi fast nie :P

Dann packt man eh sein Kram gescheit als Package in den Python Package Index: https://pypi.python.org/pypi

Dann muß man auch immer an die Zielgruppe denken. Leute unter Linux nutzten einfach pip und alles gut. Dann ist es vollkommen egal, wie viele Dateien das Ding hat...

Für Windows-Otto-Normalo ist das allerdings eine andere Geschichte. Dazu hatte ich auch eine Idee: http://www.python-forum.de/viewtopic.php?f=1&t=35061

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sirius3 hat geschrieben:@jens: es ist auf jeden Fall sinnvoll, logisch zusammengehörende Einheiten in einzelne Frames zu packen, um sowohl logisch, als auch im Fenster eine Hirachie aufzubauen. Was mich an Deinem Beispiel etwas stört ist, dass sich die LabelFrames selbst platzieren. Das ist eigentlich die Aufgabe der höheren Instanz. Bei Label oder Button rufst Du ja auch danach die grid-Methode auf.
Das ist doch mal ein Sachdienlicher Hinweis :P

Die Platzierungs-Information kommt ja von Außen. Aber unschön und unlogisch ist es schon!
Hab das Beispiel mal geändert:

[codebox=python file=Unbenannt.txt]import tkinter as tk


class Outputs(tk.LabelFrame):
def __init__(self, master):
tk.LabelFrame.__init__(self, master, text="LCD-Ausgabe")

self._lbl = tk.Label(self, text="Foo", anchor="e")
self._lbl.grid(column=0, row=0, sticky="e")

self._var = tk.StringVar()
self._entry = tk.Entry(self, textvariable=self._var)
self._entry.grid(column=1, row=0, sticky="nse")

self._btn = tk.Button(self, text="Zeile löschen")
self._btn.grid(column=3, row=0, sticky="nse")


class Inputs(tk.LabelFrame):
def __init__(self, master):
tk.LabelFrame.__init__(self, master, text="Eingabe")

self._lbl = tk.Label(self, text="Foo", anchor="e")
self._lbl.grid(column=0, row=0, sticky="e")

self._var = tk.StringVar()
self._entry = tk.Entry(self, textvariable=self._var)
self._entry.grid(column=1, row=0, sticky="nse")

self._btn = tk.Button(self, text="Zeile löschen")
self._btn.grid(column=3, row=0, sticky="nse")


class Buttons(tk.LabelFrame):
def __init__(self, master):
tk.LabelFrame.__init__(self, master, text="Ein paar Buttons")

for no, txt in enumerate(["bla blub", "foo bar"]):
self._btn = tk.Button(self, text=txt)
self._btn.grid(column=no, row=0, sticky="nse")

for no, txt in enumerate(["noch einer", "ende"]):
self._btn = tk.Button(self, text=txt)
self._btn.grid(column=no, row=1, sticky="nse")


class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Foo Bar")

self.add_Widgets()

self.mainloop()

def add_Widgets(self):
padding = 5
defaults = {
"ipadx": padding, # add internal padding in x direction
"ipady": padding, # add internal padding in y direction
"padx": padding, # add padding in x direction
"pady": padding, # add padding in y direction
"sticky": tk.NSEW, # stick to the cell boundary
}

self.outputs = Outputs(self)
self.outputs.grid(column=0, row=0, **defaults)

self.inputs = Inputs(self)
self.inputs.grid(column=0, row=1, **defaults)

self.actions = Buttons(self)
self.actions.grid(column=1, row=0, rowspan=2, **defaults)


if __name__ == '__main__':
App()[/code]

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
David_123
User
Beiträge: 8
Registriert: Montag 26. Juni 2017, 12:40

Bin ich froh diesen Thread gefunden zu haben. Ich bin auf der Suche nach Logik!
Nach meinen ersten Schritten in Python mit tkinter GUI und etwas OOP frage ich mich immer wieder wie baue ich das Programm am gescheitesten auf. Ich finde es sehr schwer dazu Hinweise zu finden. Trennen von GUI und Berechnung ist klar (in dem Zusammenhang habe ich mir auch schon was über Model View Controller erzählen lasse). Aber jetzt frage ich mich wie ich das GUI am besten strukturiere. Programm wächst halt langsam und wird immer verknoteter. Dieser Ansatz hier scheint ganz gut zu sein. Danke dafür! Wenn Ihr noch Literaturtipps oder Links zu dem Thema habt, würde ich mich freuen, diese hier zu lesen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@David_123: dieser Thread ist doch schon uralt.
Aber schau Dir doch mal meinen GuiDesigner an. Da fehlt es noch an Doku.
Aber das Grid Layout ist ganz schön beschrieben.

https://github.com/AlfonsMittelmeyer/py ... -messaging

Und komplexe GUIs sind damit kein Problem. Denn für komplexe GUIs und klare Strukturierung ist er gemacht und globaler Murks wird nicht gefördert - obwohl natürlich auch da mit Gewalt möglich.
Antworten