Wie auf Objekte der „übergeordneten“ (?) Klasse zugreifen?

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
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo,

ich habe hier ein Qt-Programm in dem ein zweites Fenster geöffnet wird. In dem Hauptfenster habe ich ein Objekt einer Klasse erstellt, auf das ich im zweiten Fenster zugreifen möchte. Nur wie mache ich das am besten?

Stark reduziert hab ich das jetzt so gemacht:

Code: Alles auswählen

class MainWindow(QtGui.QDialog):
    def __init__(self):
        #...
        self.databaseconnection = Database(databasefile)

    def openServerDialog(self):
        serverwindow = ServerSetup()
        serverwindow.show()

class ServerSetup(QtGui.QDialog):
    def __init__(self):
        pass
Ich möchte jetzt in der ServerSetup-Klasse auf dieses self.databaseconnection zugreifen können. Ich könnte ja einfach

Code: Alles auswählen

    def openServerDialog(self):
        serverwindow = ServerSetup(self.databaseconnection)

class ServerSetup(QtGui.QDialog):
    def __init__(self, databaseconnection):
        pass
schreiben. Allerdings frage ich mich, ob es da keine bessere Lösung für gibt, als alle relevanten Objekte zu übergeben?

Danke!
BlackJack

@Hellstorm: Was sollte es denn für eine bessere Lösung geben? Genau wie man bei Funktionen alles was man braucht als Argumente übergibt, macht man das bei Klassen auch.

Was Du allerdings hier „vergessen” hast, ist das Qt-Objekte in der Regel immer ein Elternobjekt übergeben werden sollte, weil Qt sonst mit der Speicherverwaltung durcheinander kommen kann. In sofern müsstest Du dem `ServerSetup()` in `openServerDialog()` sowieso schon mal `self` übergeben und in der `ServerSetup.__init__()` dann auch die QtGui.QDialog.__init__() damit aufrufen.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Danke für die Antwort!

Mir kam das nur eventuell etwas komisch vor, wenn man von der zweiten Klasse viel in der ursprünglichen Klasse bearbeitet. Da fand ich es ein wenig komisch, wenn man da so viel übergeben müsste. Aber wenn das so normal ist, dann ist es ja in Ordnung.

Zu Qt: Ah, das wusste ich nicht. Danke :)
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo noch einmal,

ich wollte nur fragen, ob ich das jetzt so richtig gemacht habe? Funktionieren tut es ja, aber das tut es ja auch oft, selbst wenn es falsch ist :D

Code: Alles auswählen

    
class MainWindow(QtGui.QDialog):
    def openServerDialog(self):
        serverwindow = ServerManager(self, self.databaseconnection)
        serverwindow.show()

class ServerManager(QtGui.QDialog):
    def __init__(self, parent, database_connection):
        QtGui.QDialog.__init__(self, parent)
        self.ui = uic.loadUi("ui/server.ui", self)
        self.ui.show()
Danke :)

Achja, brauche ich eigentlich das self.ui.show() in ServerManager.__init__? Oder wo sollte das am besten hinein?

Edit:
Ah, wobei, jetzt hab ich das glaub ich alles ein wenig besser verstanden! Ich kann ja durch Übergabe des Elternobjektes „self“ einfach das gesamte Elternobjekt übergeben und anschließend so auf alle Objekte im Elternobjekt zugreifen, richtig?

Ich habe das jetzt so gemacht:

Code: Alles auswählen

    
class MainWindow(QtGui.QDialog):
    def openServerDialog(self):
        serverwindow = ServerManager(self)
        serverwindow.show()

class ServerManager(QtGui.QDialog):
    def __init__(self, parent):
        QtGui.QDialog.__init__(self, parent)
        self.ui = uic.loadUi("ui/server.ui", self)

        self.database = parent.databaseconnection
Richtig? Also funktionieren tut es.
BlackJack

@Hellstorm: Ob man das so macht oder lieber die Sachen die man im Kindobjekt (bezogen auf die GUI-Hierarchie) benötigt einzeln übergibt ist Geschmackssache. Was dagegen spricht, ist dass das Kindobjekt dann Annahmen über das übergebene Elternobjekt treffen muss. Und man sieht beim Lesen nicht so einfach *was* alles verwendet wird. Wenn man das explizit übergibt, bekommt man auch einfacher mit wann es anfängt zu viel zu werden und man vielleicht am Entwurf etwas ändern sollte.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Ah ok, das erscheint logisch. Na dann werde ich es doch wieder einzeln hineinschreiben. Danke!
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Hellstorm: Ich würde - ähnlich wie BlackJack - eher eine Instanziierung mittels `ServerManager(self, self.databaseconnection)` bevorzugen. Ein solches Vorgehen ist flexibler und entkoppelt den `ServerManager` besser vom Eltern-Widget. Spätestens wenn man bei deinem jetzigen Code dieses Detail ordentlich dokumentieren möchte, dann ist es IMHO nämlich blöde zu sagen, dass der `ServerManager` ausschließlich mit Eltern-Widgets umgehen kann, die ein `.databaseconnection`-Attribut haben. Bei einer expliziten Übergabe hingegen erspart man dem Nutzer der `ServerManager`-Klasse nicht nur den Zwang zur fixen Benennung des Attributs vom Eltern-Widget, sondern man fordert nicht mal, dass das übergebene Widget überhaupt eine Datenbank-Verbindung mitbringen muss. Die Verbindung könnte im vorliegenden Beispiel dann theoretisch auch von woanders her als von der `MainWindow()`-Instanz kommen.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Zitat aus dem ersten Beitrag:
Hellstorm hat geschrieben:Allerdings frage ich mich, ob es da keine bessere Lösung für gibt, als alle relevanten Objekte zu übergeben?
Naja, bisher sehe ich nur ein einziges zu übergebenes Objekt. Wenn es sehr viele werden, empfiehlt sich immer die Nutzung einer Hilfsklasse wie z.B. collections.namedtuple, welche die ganzen nötigen Konfigurationsdaten bereitstellt, um möglicherweise "ewig lange" Funktionssignaturen zu vermeiden. Alternativ zu `namedtuple` bietet sich die Verwendung eines `dict()`s an, wo halt dementsprechend aussagekräftige Namen für die einzelnen Konfigurationspunkte als Schlüssel gewählt werden.
Antworten