Mein erstes Programm mit GUI (PyQt) - FEEDBACK

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
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

Hallo zusammen!

dies wird wohl ein etwas längerer Text, also seid an dieser Stelle gewarnt!

Seit knapp einem 3/4 Jahr beschäftige ich mich nun mit Python.
Etliche (teilweise sehr hakelige) Übungsaufgaben habe ich in der Zeit gemacht und
viele kleine Programme für (seien wir ehrlich) sinnlose Problemstellungen geschrieben. Dies klappte manchmal mehr, mal weniger gut und oft war ich auch am verzweifeln - das wichtigste jedoch, den Spaß an der Programmiererei habe ich dadurch nicht verloren und sicherlich auch so einiges dabei gelernt.

Jetzt wollte ich nur endlich einmal etwas "sinnvolles" tun. Ein Programm mit einer richtigen GUI das auch für irgendetwas gut ist.
So kam ich auf die Idee eines Aroma-Rechners. An dieser Stelle ist wohl ein kleiner Exkurs in die Welt der E-Zigarette-Dampfer angebracht (für die jenigen die sich damit nicht so genau auskennen):

E-Zigaretten verdampfen ein Liquid bestehend aus einer Base (meist eine Mischung aus Propylenglcol und Glycerin) und Lebensmittelaromen. Diese Liquids kann man fertig kaufen oder aber - hier kommt mein Projekt ins Spiel - selber mischen.
Ein solches "Rezept" schaut dann z.B. wie folgt aus:
Das Liquid "Würgreiz-Extreme" besteht aus den Aromen:

- Erdbeere: 1%
- Banane: 2%
- Brathähnchen: 5%

Der Rest wird mit Base aufgefüllt.

Zugegeben, es gibt bereits dutzende solcher Rechner, aber ich hielt es dennoch für eine nette Aufgabe mir selber einen zu basteln.

Bild
https://ibb.co/Fw141D0

Verkneift euch bitte das Lachen, aber das ist dabei herausgekommen. :D
Verwendet habe ich für das GUI PyQt.

Den Design-Part habe ich aufjedenfall unterschätzt. Hier trafen mangelnde Kreativität und CSS-Skills aufeinander. Aber das ist eigentlich für mich erst einmal nebensächlich.
Viiiel schlimmer schaut jedenfalls der Code hinter alle dem aus, den ich hier mit voller Absicht mal lieber nicht zur Schau stelle. :D
Aber dennoch: Die grausig geschriebenen 500 Zeilen Anfänger-Code tun ihren Job und das Programm funktioniert.

Da das Ganze nun am Ende doch keine Komplexität eines Adobe Photoshops hat und relativ gradlinig verläuft, beschreib ich die Funktion mal schrifltich:

Button "Aroma hinzufügen" ist dafür zuständig, die 3 Textfelder Name, Menge, Preis auszulesen und in die Tabelle "Meine-Aromen" einzufügen.
Durch einen Klick auf "Aroma Liste speichern" werden aus dem Inhalt der Tabelle Aroma-Objekte (Klasse) erzeugt und in einem "Aroma-Manager" (Klasse) mit einer ID in einem Dictionary gespeichert. Zusätlich werden die Aroma-Daten in einer Text-Datei als Tupel abgespeichert.
Lädt man das Programm neu, wird die Aroma-Text-Datei ausgelesen und die Aroma-Objekte neu geladen.

Der Button "Hinzufügen" nimmt sich das derzeitige Aroma und die zugehörige Dosierung aus der Spinbox und fügt es der Tabelle "Neues Rezept" hinzu. Wird der Haken "Alles drin?" gesetzt, erscheint ein weiteres Text-Feld, in dem man einen Namen für das Rezept eingibt und es dann abspeichert / ein Rezept-Objekt (Klasse) erstellt. Das Rezept-Objekt wird wiederum im Rezept-Manager in einem Dictionary abgelegt (wieder wie bei den Aroma-Objekten). Optional kann man das Rezept dann wieder "abspeichern", dafür gibts dann eine weitere Text-Datei, die dann auch wieder bei Programm Neustart zuerst geladen bzw. ausgelesen wird.

In der ComboBox "Meine Rezepte" werden nun die Namen der existierenden Rezepte angezeigt. Das derzeit ausgewählte Rezept wird in der Info-Box rechts (siehe Bild) angezeigt. Man wählt nun eins aus, gibt die Menge des herzustellenden Liquids ein und mit "Mix it!" wird ganz Rechts in der Info-Box das fertige Rezept angezeigt (auf dem Bild nicht zu sehen) (zzgl. der Aroma-Kosten). Außerdem wird die Tabelle "Meine-Aromen" dann aktualisiert. Also die für das "gemischte Rezept" verwendeten Aroma-Mengen von den jeweiligen Mengen abgezogen.

Nun endlich mein "Problem" mit dem Ganzen:
Das ganze besteht aus 6 Klassen (Aroma, Aroma_Manager, Rezept, Rezept_Manager, Read_and_write und eben der Main)
Die ersten 4 dürften was die Funktion betrifft selbsterklärend sein, read_and_write befasst sich mit der Daten speicherung bzw. dem Auslesen der Text-Dateien.
Und dann ist da eben die Main...
In ihr läuft die komplette GUI-Logik (Design, Buttons, Tabellenfunktionen....) und auch alles andere an "Logik".

Nun meine banale Frage: Wie würde ein "Profi" ein solches Programm gestalten?
Denn auch wenn ich während der Arbeit an dem Ganzen viel Lernen konnte, bin ich eben nicht so richtig zufrieden und würde es gerne nochmal alles Neu machen. Dann aber "besser". Einige Ideen, habe ich bereits z.B. keine einfache Text-Datei mehr zur Speicherung zu verwenden sondern eine .CSV und auch an der Objekt-Verwaltung würde ich gern nochmal schrauben...
Wo ich aber immer noch etwas auf dem Schlauch stehe: Wie bekomme ich Ordnung in das Ganze?

Würde mich einfach über jegliche Art Tipps und Feedback freuen!
Benutzeravatar
__blackjack__
User
Beiträge: 14067
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ElastischerHosenbund: Ich würde als erstes mal nichts ”designen” sondern für den Anfang erst einmal eine normale GUI erstellen die sich an den Erwartungen der Benutzer orientiert. Und das dann auch mit Layouts, denn das Bild sieht nicht so aus als wenn die verwendet wurden. Das sieht nach absoluten Positionen und Grössen aus. Das skaliert nicht.

Falls die 500 Zeilen Code durch die GUI-Elemente kommt: die würde ich mit dem Qt-Designer erstellen und zur Laufzeit die *.ui-Datei laden.

Die Klassennamen halten sich nicht an den Style Guide for Python Code und das `Manager` klingt verdächtig nach Java. `Manager` bedeutet nichts. Jede Klasse verwaltet irgendwie Zustand und damit kann man auch an jeden Klassennamen ein `Manager` dran pappen.

Die Klasse zum lesen/schreiben mutet auch javaesque an. Warum ist das eine Klasse? Welcher Zustand steck da drin? Oder sind das einfach nur Funktionen die in eine Klasse gestopft wurden? Python hat für Funktionen — nun ja: Funktionen!
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
DeaD_EyE
User
Beiträge: 1242
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

__blackjack__ hat geschrieben: Mittwoch 1. September 2021, 21:52 Falls die 500 Zeilen Code durch die GUI-Elemente kommt: die würde ich mit dem Qt-Designer erstellen und zur Laufzeit die *.ui-Datei laden.
Oh ja, das spart Tipparbeit und Copy&Paste-Fehler.
Vorteilhaft ist auch, dass man mehrere ui-Dateien laden kann und diese in das Programm einzubinden.
Design sollte man immer vom Code trennen so weit es geht.

Man kann sogar DummyKlassen in Qt Designer erstellen, womit man dann externe Widgets laden kann.
So habe ich z.B. eine analoge Uhr mit eingebunden. Man sieht die Widgets dann aber erst zur Laufzeit des Programms und nicht im Designer.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

Erst danke für Eure Antworten!
Version 2 ist in Arbeit :D
Diesmal auch mit Layouts dafür aber etwas "konservativer" im Stil... An der anordnung des Ganzen werd ich nochmal etwas machen müssen und die Farben sind auch noch nicht gesetzt... Aber das lässst sich ja alles noch ändern
Bild
https://ibb.co/nM7VJTD


Nun nochmal zum eigentlichen:
Das Programm soll ja die Daten der erstellten Aroma- und Rezept-Objekte speichern können um sie nach Neustart neu laden zu können.
In V1 habe ich das eben stumpf mit einer .txt-Datei gemacht. Daten in String umgewandelt, ins Dokument geschrieben und dann wieder geladen. Das war alles etwas hakelig... Gibt es da nicht eine bessere Lösung?
Ansonsten wäre mein Plan nun in V2 das ganze mit .csv Dateien zu gestalten.. Das dürfte eigentlich etwas umgänglicher sein (glaub ich zumindest :D)

Und dann noch die interne "Objekt-Verwaltung"... Wie gestaltet man die am besten? In v1 habe ich das wie gesagt mit den "Manager" Klassen und einem Dictionary getan. Wie würdet ihr das machen?

Btw: Die Klasse "read_and_write" war tatsächlich nur eine Klasse, in die ich alle Funktionen gestopft habe.. Es erschien mir so "ordentlicher" diesen Teil "auszulagern".. Auch wenns nun falsch war... Wo würdet ihr die Funktionen mit reinpacken?

Das ist nämlich noch meine große Unsicherheit: Wie "ordne" ich das alles? Ich habe irgendwo mal von einem Designpattern "MVC" gelesen..
Model (Die komplette Programmlogik? Mitsamt den eben angesprochenen Funktionen für die Daten?)
View (das wäre dann ja meine .ui datei und damit fertig)
Controller (Funktionen für die Benutzereingabe die dann ans Model weitergegeben werden?)

Würd mich über weitere Tipps freuen!
Benutzeravatar
__blackjack__
User
Beiträge: 14067
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ElastischerHosenbund: Für's speichern eignen sich verschiedene Formate. Am besten nichts selbst gebasteltes, wenn man auch etwas Standardisiertes nehmen kann. CSV eignet sich für ”zweidimensionale” Daten. JSON wäre vielleicht auch eine Option für die es in der Standardbobliothek ein Modul gibt. Auch eine SQL-Datenbank käme in Frage. Wo es mit SQLite 3 auch etwas in der Standardbibliothek gibt was auch ohne Server auskommt.

Was steckt denn in den Managerklassen über die Wörterbücher hinaus? Kann man da vielleicht auch jeweils einfach ein Wörterbuch verwenden?

Funktionen gehören in gar keine Klasse. Warum willst Du die unbedingt (mit) in eine Klasse stecken?

Vergiss MVC so ganz allgemein am besten. Verschiedene GUI-Rahmenwerke verstehen das unterschiedlich und die drei Teile braucht man auch selten wirklich. Es macht Sinn wenn man es braucht. Sonst landet man schnell in der Situation das man ein Entwurfsmuster hat und ein Problem dafür sucht, und nicht umgekehrt, wie es sein sollte.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

JSON wollte ich mir schon immer einmal genauer anschauen. Dann werd ich mich da mal reinarbeiten. SQL wäre für das ganze glaube ich etwas "overkill".

In den Managerklassen steckte sonst nichts. Nur die jeweiligen Aroma- bzw. Rezept-Objekte zusammen mit einer ID als Key in einem Dictionary (und eben die jeweiligen Methoden um drauf zuzugreifen).
Mein banaler Gedankengang orientierte sich dabei an Karteikästen (die Managerklassen) in die man seine Karten (Aroma und Rezept-Objekte) einsortiert.
"Funktionen gehören in gar keine Klasse" Glaube das habe ich dann mit "Methoden" verwechselt. ^^

Bzgl: MVC: Wie könnte man das denn dann noch machen? GUI und Programmlogik sollen ja weitestgehend getrennt sein wie hier auch schon angemerkt wurde.
Gibts im Netz evtl. irgendwo vom Umfang vergleichbare Projekte wo ich mir den Aufbau einmal ansehen kann? In meinen Lernunterlagen gehen die Beispiele leider nie über "Bauen Sie einen BMI-Rechner" hinaus, geschweigedenn schließen PyQt und .ui Dateien mit ein.
Benutzeravatar
__blackjack__
User
Beiträge: 14067
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ElastischerHosenbund: Naja, einfach Programmlogik und GUI trennen. Wobei die Programmlogik hier ja recht übersichtlich ist. Und es hängt auch vom GUI-Rahmenwerk ab. Qt hat beispielsweise sein Model/View-Rahmenwerk was auch ausführlich dokumentiert ist und für das es auch Beispiele gibt in der Dokumentation. Also in der C++-Dokumentation. Auf die wird man letztlich sowieso zugreifen (müssen), denn das übersetzt niemand extra nach Python. Das macht mehr Aufwand als es Nutzen bringt.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

Hmm... Nagut.. Ich leg einfach mal drauf los ... :D
Antworten