Infos zwischen parent und Child-Window austauschen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

Hallo,

ich habe da mal eine Verfahrensfrage. Ich habe Ein Mainwindow und mehrere, weitere Mainwindows, die quasi Childs des Hauptfensters sind.

Code: Alles auswählen

class Sub1(QMainWindow)
  def __init__(self, parent=None)
    self.directory = parent.directory

class Sub2(QMainWindow)
  def __init__(self, parent=None)
    self.directory = parent.directory

class Sub3(QMainWindow)
  def __init__(self, parent=None)
    self.directory = parent.directory

class Main(QMainWindow)
  def __init__(self, parent=None)
    self.directory = environt['USERPOFILE']

So grob ist meine Struktur. Was ich jetzt gern hätte, ist dass wenn ich ein Subwindow aufrufe, er das Verzeichnis vom Main bekommt. Das klappt ja soweit schon. Jetzt möchte ich aber, wenn ich das SubWindow verlasse, auch den Pfad wieder zurückgeben. Also den aktuellen Pfad von SUB1 an Main übergeben.

Aufrufen tue ich die SUBs folgendermaßen in der Main

Code: Alles auswählen

self.sub1 = Sub1()
self.sub1.show()
Da die Fenster alle NonModal sind, kann ich nicht im Anschluss an show() einfach

Code: Alles auswählen

self.directory = self.sub1.directory
machen.

das ganze über den Dekonstruktor zu machen funktioniert auch nicht, da sich das Objekt beim schließen des Fensters nicht zerstört. Warum eigentlich nicht? Kann ich das provozieren? Sollte man das machen. Hat das einen Vor-/Nachteil?

Ideen?

Gruß,
Steffen
lunar

Du hast Hauptfenster, die an ein anderes Hauptfenster Werte zurückgegeben sollen?! Das ist ein recht merkwürdiger Entwurf. Für die Abfrage eines Verzeichnisses nutzt man normalerweise Dialoge, und da könntest Du Dir die API einfach von den existierenden Dialogen in Qt abschauen.
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

oder sagen wir es einfach so ... meine Applikation besteht aus mehreren Teilapplikationen.
Eine Hauptapplikation ist quasi ein Starter für alle anderen Teile.
Es gibt in den einzelnen Teilen immer wieder Möglichkeiten Dateien zu laden/speichern etc. Das Startverzeichnis des QFileDialog soll jetzt immer das zuletzt benutzte Verzeichnis sein, so lange die HaupApplikation geöffnet ist.

Szenario:
  • starte Main (Dir=C:\)
    starte sub1 (Dir=C:\)
    öffne datei in sub1 (d:\temp\eins.txt)
    schließe sub1
    starte sub2 (Dir=d:\temp)
    ...
Ich hoffe es ist klar, was ich vor habe.



Gruß,
Steffen
BlackJack

@knumskull: Das hört sich für mich an als wenn Du GUI und Anwendung nicht sauber trennst. Ansonsten hätte das Anwendungsobjekt, welches den Teil der Anwendung modelliert, den sich alle Unteranwendungen teilen, eine Möglichkeit sich den zuletzt verwendeten Pfad zu merken. Im einfachsten Fall ein Attribut. Und auf dieses Objekt müssen dann alle "Hauptfenster" der Teilanwendungen Zugriff haben.

Falls Du mit "Dekonstruktor" die `__del__`-Methode meintest: Lass die Finger davon. Die funktioniert nicht so wie man vielleicht denkt oder wünscht. Da gehört nichts hinein auf dessen Ausführung man sich verlassen können muss, und allein die Existenz der Methode kann unter bestimmten Umständen verhindern, dass ein Objekt jemals aus dem Speicher entfernt werden kann.
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

BlackJack hat geschrieben:Das hört sich für mich an als wenn Du GUI und Anwendung nicht sauber trennst. Ansonsten hätte das Anwendungsobjekt, welches den Teil der Anwendung modelliert, den sich alle Unteranwendungen teilen, eine Möglichkeit sich den zuletzt verwendeten Pfad zu merken. Im einfachsten Fall ein Attribut. Und auf dieses Objekt müssen dann alle "Hauptfenster" der Teilanwendungen Zugriff haben.
okay, das kann gut sein. Ich gebe auch zu, dass ich in dem Fall etwas schlampig war, bzw. der Code der mir vermacht wurde auch sehr unsauber war, so dass ich größtenteils damit leben muss. (vorerst)
Aber zurück zum Thema.

So ganz habe ich noch nicht verstanden, was du damit meinst. Also klare Trennung zw. GUI und Anwendung. Wie würdest du so was gestalten, wie ich es vor habe? Ein Beispiel-Kontrukt würde mir sehr helfen. Ich kann mir das gerade nicht einmal in der Theorie vorstellen, wie das gehen soll :-). Irgendwie ist da ein Brett vorm Kopf.

Danke im Voraus.
BlackJack hat geschrieben: Falls Du mit "Dekonstruktor" die `__del__`-Methode meintest: Lass die Finger davon. Die funktioniert nicht so wie man vielleicht denkt oder wünscht. Da gehört nichts hinein auf dessen Ausführung man sich verlassen können muss, und allein die Existenz der Methode kann unter bestimmten Umständen verhindern, dass ein Objekt jemals aus dem Speicher entfernt werden kann.
okay, gut zu wissen. Dann kann ich meinen Test mit der Methode also bedenkenlos löschen :-)

Gruß,
Steffen
BlackJack

@knumskull: Ich weiss nicht so recht was ich da jetzt als Beispiel schreiben soll, denn es geht im einfachsten Fall ja tatsächlich nur um ein ganz einfaches Attribut auf einem Objekt zu dem ich ausser diesem Attribut nichts weiter sagen kann, weil es eben die Anwendungslogik implementiert. Die kenne ich ja nicht. Falls die Teilanwendungen wenig bis gar keine gemeinsame Daten oder gemeinsames Verhalten haben, dann könnte man stattdessen auch ein Objekt nehmen, das die Konfigurationsdaten der Gesamtanwendung aufnimmt.
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

BlackJack hat geschrieben: Falls die Teilanwendungen wenig bis gar keine gemeinsame Daten oder gemeinsames Verhalten haben, dann könnte man stattdessen auch ein Objekt nehmen, das die Konfigurationsdaten der Gesamtanwendung aufnimmt.
Das ist ja so ungefähr mein Fall. Wie würdest du in diesem Fall das Objekt definieren? Und wie würdest du die Zuweisung der Daten zur Laufzeit machen?

Also gemeinsame Methode und Klassen zu verwenden ist ja einfach. Das kann ich ja einfach durch import erledigen.
BlackJack

@knumskull: Ich habe irgendwie Probleme zu verstehen wo das Problem ist. Die GUI-Exemplare für die Haupt-GUI und die verschiedenen Teilprogramme bekommen beim erstellen das Objekt, welches die Anwendungslogik implementiert übergeben. Und wenn das für alle das gleiche Objekt ist, kann man da halt auch den Pfad vermerken.
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

@BlackJack: Ich habe irgendwie das Problem zu verstehen, was du mir sagen willst :). Ich weiß was du mir sagen willst (hoffe ich), kann mir das aber schlecht in Python vorstellen.

Ich weiß nicht so recht, wie du das mit dem Objekt meinst. Kannst du mir da ein Beispiel geben. Muss mit dem eigentlichen Problem nichts zu tun haben, aber vielleicht hilft es, um mein Brett vorm Kopf zu entfernen.

Das einzige was ich bis jetzt an "Übergabe"-Methoden kenne, ist als Parameter oder halt Vererbung. Aber damit wüsste ich nicht, wie ich das umsetzten sollte.
BlackJack

@knumskull: Äh, ein Beispiel:

Code: Alles auswählen

class A(object):
    def __init__(self, x):
        self.x = x
Wenn man ein Exemplar von `A` erstellt, muss man ein Objekt übergeben und das wird an ein Attribut gebunden und die Methoden von dem `A`-Exemplar können darauf dann zugreifen, Methoden aufrufen und Werte setzen. Und `A` ist eben die GUI oder Teil-GUI und `x` die Anwendungslogik oder ein Konfiguratiosobjekt was einfach nur Werte speichert. Und so muss dann halt jede (Teil-)GUI-Klasse gestrickt sein, und Du musst allen beim Erstellen das selbe Objekt mitgeben.
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

@BlackJack: Okay, dass ist doch die gleiche Methode, wie ich mit parent in meinem ersten Post geschrieben habe. So kann ich natürlich einen Wert in die neue Instanz hineinbringen. Aber wenn sich der Wert innerhalb ändert, wie bekomme ich den Wert wieder zurück?

Code: Alles auswählen

class A(object):
    def __init__(self, x):
        print('calling %s' % self.__class__)
        self.x = x
    
    def out(self):
        print("at: %s; Value: %s" % (self.__class__, self.x))

    def change(self):
        self.x += 1
        
if __name__ == '__main__':
    def out(x):
        print("at: %s; Value: %s" % (__name__, x))
    
    x = 0
    
    out(x)
    obj = A(x)
    obj.out()
    obj.change()
    obj.out()
    out(x)
Der Output ist dann folgendermaßen:

Code: Alles auswählen

at: __main__; Value: 0
calling <class '__main__.A'>
at: <class '__main__.A'>; Value: 0
at: <class '__main__.A'>; Value: 1
at: __main__; Value: 0
Allerdings möchte ich es, dass der Wert am Ende in der __main__ auch wieder '1' ist.
BlackJack

@knumskull: Du änderst den Wert ja gar nicht, Du bindest einen komplett anderen Wert an das Attribut. *Das* bekommt natürlich "ausserhalb" keiner mit. Verwende ein veränderliches Objekt. Im einfachsten Fall vielleicht ein Dictionary.

Code: Alles auswählen

class A(object):
    def __init__(self, config):
        self.config = config
    
    def do_something(self):
        user_input = raw_input('Eingabe: ')
        self.config['spam'] = user_input
        print 'Do something with %r' % user_input


class B(object):
    def __init__(self, config):
        self.config = config
    
    def do_even_more(self):
        print 'Do more with %r' % self.config['spam']


def main():
    config = dict()
    a = A(config)
    b = B(config)
    a.do_something()
    b.do_even_more()
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

Ah Super. Das sollte mein Problem lösen. Ist noch alles ein bisschen ungewohnt.
Danke.

Ein Frage habe ich noch. Was bedeutet das %r beim print-statement Mir sind nur %d & %s bekannt.
knumskull
User
Beiträge: 34
Registriert: Dienstag 29. September 2009, 08:07
Kontaktdaten:

Super. Ich wusste auch nicht auf Anhieb, unter welchem Punkt ich suchen sollte.

Danke. Jetzt kann ich getrost das Problem angehen.
Antworten