Mehrere Probleme mit Tkinter und Objektorientierung...

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
Agroschim
User
Beiträge: 28
Registriert: Sonntag 16. September 2007, 15:19

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]
BlackJack

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.

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
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.
Benutzeravatar
Agroschim
User
Beiträge: 28
Registriert: Sonntag 16. September 2007, 15:19

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?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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?
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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Agroschim
User
Beiträge: 28
Registriert: Sonntag 16. September 2007, 15:19

Ich begreife es nicht. Tut mir leid.
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

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.
Benutzeravatar
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.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
Agroschim
User
Beiträge: 28
Registriert: Sonntag 16. September 2007, 15:19

Ich schreibe es die Tage mal von Grund auf neu...
Antworten