Qt5 Zwischen Fenstern wechseln / Steuerung von Window1 aus Window2

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
radi
User
Beiträge: 8
Registriert: Freitag 15. Januar 2021, 12:15

Hi zusammen,

ich habe ein Haupt-Gui und öffne daraus per pushbutton ein neues Window:

Code: Alles auswählen

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()  # sets ui = to the main window from the ui-file
        self.ui.setupUi(self)
        [...]
        
    def enter_fct_results(self):
        self.FCTpopup = FCT_Window()
        self.FCTpopup.show()
dort füllt man einen QTable und den schicke ich an ein Funktion über connect zurück:

Code: Alles auswählen

class FCT_Window(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_FCT_Window()
        self.ui.setupUi(self)
    [...]
 
    def on_submit(self):  # event when user clicks
          fct_nparray = np.zeros((self.ui.tableFCTinputs.rowCount(), self.ui.tableFCTinputs.columnCount()))
              for j in range(self.ui.tableFCTinputs.columnCount()):
                    for i in range(self.ui.tableFCTinputs.rowCount()):
                        fct_nparray[i, j] = float(self.ui.tableFCTinputs.item(i, j).text())
          return  fct_nparray, lambda: self.close()

Code: Alles auswählen

self.ui.pushButton_submitFCT.clicked.connect(lambda: MainWindow.store_fct_data(MainWindow, self.on_submit()[0]))
Gleichzeitig schließt sich das Fenster "FCTpopup". Der Slot ist in dieser Funktion und legt den Array einfach in einer Variable ab:

Code: Alles auswählen

    def store_fct_data(self, data):
        self.fct_data = data
Jetzt möchte ich eigentlich nur eine triviale Sache hinzu fügen und zwar, dass sich nicht mehrere Instanzen vom FCTpopup öffnen können wenn man enter_fct_results() mehrfach aufruft. da dachte ich, packste einfach self.ui.pushbuttonFillArray.setEnabled(0) hinzu und entweder im return mit dem schließen vom FCT_window soll der Button wieder enabled werden aber ich bekomme immer fehler. Ich konnte self.ui.pushbuttonFillArray.setEnabled(1) auch nicht in "def store_fct_data" integrieren.

Code: Alles auswählen

    self.ui.pushButton_FCTresults.setEnabled(1)
    self.ui.pushButton_submitFCT.clicked.connect(lambda: MainWindow.store_fct_data(MainWindow, self.on_submit()[0]))
    AttributeError: type object 'MainWindow' has no attribute 'ui'
Könnt ihr sehen woher das kommen kann? Datenaustausch geht 1a aber wenn ich von einem Fenster die QWidgets oder so ansprechen will, hab ich noch nciht ganz verstanden wie man das machen muss. Ich lese in foren immer wieder wie toll die Qt Dokumentation ist, aber das kann ich noch nicht zu 100% nachvollziehen. Vll könnt ihr mir helfen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@radi: Das ist erstmal nicht wirklich ein Qt-Ding, hier wird ganz grundlegend beim Thema objektorientierte Programmierung was falsch gemacht: `MainWindow` ist eine Klasse aus der man ein Fenster erzeugen kann, das ist selbst kein Fenster. Du brauchst in dem neuen Fenster aber tatsächlich ein Fenster wo Du `store_fct_data()` drauf aufrufst. Die Klasse `MainWindow` hat kein `ui`-Attribut. Objekte die daraus erstellt werden haben das weil das in der `__init__()` angelegt wird.

Dem `FCT_Window`-Exemplar musst Du beim erstellen das Objekt mitgeben auf dem später das Ergebnis gesetzt werden soll. Das musst Du in der `__init__()` an das Objekt binden, damit da im Slot drauf zugegriffen werden kann.

Deine Fenster/Objekte wissen aber ziemlich viel voneinander. Das ``lambda: self.close()`` als Rückgabewert sieht auch komisch aus. Und wenn man mehrere von diesen Fenstern gleichzeitig öffnen kann, dann macht es keinen Sinn das an das `MainWindow`-Exemplar zu binden.

Eine sauberere Lösung wäre es dem `FCT_Window` ein Signal zu verpassen, dass als Wert die eingetragenen Daten übermittelt. Dann muss das `FCT_Window` nichts über das `MainWindow` wissen. Und das `MainWindow` registriert sich einfach als Empfänger des Signals mit den Daten und macht dann was auch immer es damit machen will.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
radi
User
Beiträge: 8
Registriert: Freitag 15. Januar 2021, 12:15

Danke für dein Feedback. Ja du hast recht, ich habe noch nicht alles verstanden und bin noch am Lernen :)

Die Datenübertragung klappt auch mittels dem hier:

Code: Alles auswählen

self.ui.pushButton_submitFCT.clicked.connect(lambda: MainWindow.store_fct_data(MainWindow, self.on_submit()[0]))
Signal ist der Button-click und der slot ist store_fct_data, welche im MainWindow in der init definiert ist.

Ich würde gerne verstehen wie ich zum Beispiel folgendes machen würde:
- Öffnen von Window2 /FCT-popup) mittels Button in Window1(MainWindow)
- Ändern der Buttonfarbe in Window1 durch Buttonclick in Window2

bin ich in der selben windowclass (also beide buttons werden durch die selbe init erstellt) kann ich ja einfach, beispiel oben nutzend, folgendes machen

Code: Alles auswählen

self.ui.pushbutton-xyz.setColor("red")
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@radi: Nein, das klappt nicht wirklich was Du da machst. Du setzt da auf kaputte Art und Weise die Daten auf der *Klasse*. Da es nur ein Exemplar davon gibt und Du das Attribut auf dem Exemplar offenbar nicht initialisierst, sieht das so aus als würde das klappen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
radi
User
Beiträge: 8
Registriert: Freitag 15. Januar 2021, 12:15

Ich habe den Fehler gefunden. Es lag an dem ort wo die connection erstellt wurde. Es muss direkt in der Methode gemacht werden, die das 2te Fenster auffruft
def enter_fct_results(self):
self.FCTpopup = Dialog(self.fct_data)
self.FCTpopup.submitted.connect(self.store_fct_data)
self.FCTpopup.exec_()
Antworten