Hallo, ich versuche mich gerade an GUIs und Objektorientiertem Programmieren. Dazu habe ich mir ein einfaches Problem gestellt: Ich will die Personen, Orte etc. die in meinen Rollenspielabenteuern vorkommen, wie in einem Karteikasten sortieren. Hier ist der vorläufige Code:
http://paste.pocoo.org/show/6982/
Nun habe ich aber folgende Probleme: Ich greife in den Klassen App und GUI auf Instanzen zurück, die noch garnicht initialisiert sind, wenn ich dauf zugreifen will, wie drücke ich mich darum? Evtl. die Instant der Klasse GUI in den __init__ Block der App-Klasse schreiben? Wäre das elegant oder gefuddelt?
Zweitens will das Copy&Paste nicht (mit globalen Namen kann ich das Problem ausschalten, will ich aber nicht). Es sieht in der Theorie so schön aus, aber mal wollen die Bindings nicht oder er will die Auswahl im Textfeld nicht löschen.
Kann mir jemand helfen?[/code]
Mehrere Probleme mit Tkinter und Objektorientierung...
Zumindest das Objekt auf dass Du über einen Namen zugreifen willst existiert bereits, es ist nur noch nicht an den Namen gebunden über den Du es versuchst.
Die Zuweisung in Zeile 120 wird erst gemacht, nachdem die `GUI.__init__()` abgearbeitet wurde. Aber das Objekt ist ja in der Methode an den Namen `self` gebunden.
Letztendlich arbeitest Du immer noch mit globalen Namen. `abenteuer`, `app`, `root` und `gui` sollten nicht auf Modulebene verfügbar sein und in einer `main()`-Funktion verschwinden. Wenn Du in einer Methode auf ein Objekt zugreifen willst, sollte das entweder an das Objekt gebunden sein auf dem die Methode aufgerufen wurde oder als Argument in die Methode hereinkommen. Alles andere macht den Programmfluss unübersichtlich und fördert unnötige Abhängigkeiten zwischen Klassen.
Code: Alles auswählen
Traceback (most recent call last):
File "forum.py", line 120, in <module>
gui = GUI(root)
File "forum.py", line 113, in __init__
gui.textfeld.bind('<Control-c>', app.copy_event)
NameError: global name 'gui' is not defined
Letztendlich arbeitest Du immer noch mit globalen Namen. `abenteuer`, `app`, `root` und `gui` sollten nicht auf Modulebene verfügbar sein und in einer `main()`-Funktion verschwinden. Wenn Du in einer Methode auf ein Objekt zugreifen willst, sollte das entweder an das Objekt gebunden sein auf dem die Methode aufgerufen wurde oder als Argument in die Methode hereinkommen. Alles andere macht den Programmfluss unübersichtlich und fördert unnötige Abhängigkeiten zwischen Klassen.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Nein, ist es nicht. Die Logik und die GUI in Programmen zu teilen ist aus einer ganzen Menge von Gründen eine gute Idee. Jedoch muss man bisschen aufpassen, dass man die Logik eben nicht mit der GUI in den einzelnen Klassen vermischt.Agroschim hat geschrieben:Das heißt also, es ist völlig unsinnig von mir, die GUI und das Programm in verschiedene Klassen zu packen, weil es Abhängigkeiten unter den Klassen generiert?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Das Grundprinzip sieht wie folgt aus:
Es gibt eine Klasse (oder auch mehrere), die das eigentliche Programm mit den gewünschten Funktionen darstellt. In deinem Fall dürfte das die Klasse Abenteuer sein. Und dann gibt es die Oberfläche, die in der Regel ebenfalls aus mehreren Klassen besteht. Beim Erzeugen einer Instanz der Oberfläche übergibst du dieser eine zuvor erzeugte Instanz der Anwendung. Alternativ könntest du diese auch in der __init__ der Oberfläche erzeugen, was ich allerdings für nicht so sauber halte.
Die Anwendung kennt die Oberfläche in der Regel nicht!
Das bedeutet vor allem, das jeglicher Code, der die Gestaltung der Oberfläche beeinflusst, in der Anwendung selbst nichts verloren hat.
Anders ausgedrückt: Die Anwendung ist praktisch ein blosser Dienstleister, der einen Satz Methoden (=Schnittstelle) zur Verfügung stellt, über die die Oberfläche sich die für die Darstellung benötigten Daten erfragen kann und ggf. Änderungen am Zustand der Anwendung anstoßen kann.
Hm. Ich glaube das ist immer noch zu theoretisch - ich werde mal überlegen, wie ich das an einem Beispiel deutlicher machen kann ...
Als erstes solltest du allerdings mal App und GUI zusammenfassen - Sie gehören inhaltlich zusammen, also gibt es keinen Grund, sie auf zwei Objekte zu verteilen. Und dann gehe die Methoden durch und überlege, welche Inhalte davon wirklich Oberflächenspezifisch sind, und welche nicht vielleicht eher in deiner Abenteuerklasse zu Hause sind. Beispiel: Das Laden und Speichern der Daten ist eigentlich Sache der Anwendung. Also schreibst du für die Abenteuerklasse zwei Methoden load und save, die als Parameter den Dateinamen haben. Diese Methoden kannst du dann vom GUI aus mit dem entsprechenden Dateinamen füttern - ob Du dem Benutzer dann einen Auswahldialog präsentierst oder den Namen sonst irgendwie abfragst ist dann Sache der Oberfläche.
Es gibt eine Klasse (oder auch mehrere), die das eigentliche Programm mit den gewünschten Funktionen darstellt. In deinem Fall dürfte das die Klasse Abenteuer sein. Und dann gibt es die Oberfläche, die in der Regel ebenfalls aus mehreren Klassen besteht. Beim Erzeugen einer Instanz der Oberfläche übergibst du dieser eine zuvor erzeugte Instanz der Anwendung. Alternativ könntest du diese auch in der __init__ der Oberfläche erzeugen, was ich allerdings für nicht so sauber halte.
Die Anwendung kennt die Oberfläche in der Regel nicht!
Das bedeutet vor allem, das jeglicher Code, der die Gestaltung der Oberfläche beeinflusst, in der Anwendung selbst nichts verloren hat.
Anders ausgedrückt: Die Anwendung ist praktisch ein blosser Dienstleister, der einen Satz Methoden (=Schnittstelle) zur Verfügung stellt, über die die Oberfläche sich die für die Darstellung benötigten Daten erfragen kann und ggf. Änderungen am Zustand der Anwendung anstoßen kann.
Hm. Ich glaube das ist immer noch zu theoretisch - ich werde mal überlegen, wie ich das an einem Beispiel deutlicher machen kann ...
Als erstes solltest du allerdings mal App und GUI zusammenfassen - Sie gehören inhaltlich zusammen, also gibt es keinen Grund, sie auf zwei Objekte zu verteilen. Und dann gehe die Methoden durch und überlege, welche Inhalte davon wirklich Oberflächenspezifisch sind, und welche nicht vielleicht eher in deiner Abenteuerklasse zu Hause sind. Beispiel: Das Laden und Speichern der Daten ist eigentlich Sache der Anwendung. Also schreibst du für die Abenteuerklasse zwei Methoden load und save, die als Parameter den Dateinamen haben. Diese Methoden kannst du dann vom GUI aus mit dem entsprechenden Dateinamen füttern - ob Du dem Benutzer dann einen Auswahldialog präsentierst oder den Namen sonst irgendwie abfragst ist dann Sache der Oberfläche.
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
In Zeile 113 bis 115 sollte es statt gui.textfeld immer self.textfeld heissen. Warum greifst du da auf einen globalen Namen zu, wenn du doch ein Attribut des gleichen Objekts ansprechen willst?
Ansonsten wuerde ich Jan-Peer zustimmen: App und GUI gehoeren in eine Klasse. Du merkst ja, dass du in App staending Attribute von dem GUI-Objekt brauchst. Ausserdem wuerde ich der GUI/App-Klasse bei der Initialisierung ein Abenteuer-Objekt als Parameter uebergeben. Das waere dann immer deine Schnittstelle von der GUI zu den Daten, darueber kannst du dann immer auf die Daten zugreifen. Das ist sauberer als mit globalen Variablen zu arbeiten.
Ansonsten wuerde ich Jan-Peer zustimmen: App und GUI gehoeren in eine Klasse. Du merkst ja, dass du in App staending Attribute von dem GUI-Objekt brauchst. Ausserdem wuerde ich der GUI/App-Klasse bei der Initialisierung ein Abenteuer-Objekt als Parameter uebergeben. Das waere dann immer deine Schnittstelle von der GUI zu den Daten, darueber kannst du dann immer auf die Daten zugreifen. Das ist sauberer als mit globalen Variablen zu arbeiten.
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei