2.Fenster schließen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
steenhy
User
Beiträge: 19
Registriert: Montag 23. März 2020, 20:22

Hallo,
eigentlich doch eine einfache Sache:
Ich möchte aus einem Hauptfenster ein 2.Fenster öffnen und dies über einen Bottom schließen und wieder ins Hauptfenster zurück.
Mit dem Kreuz oben rechts im Fenster geht es, aber wie geht es über Menü oder Bottom...?
So wird das Unterfenster geöffnet.

Code: Alles auswählen

    def Daten_erfassen(self):
        self.screen = eingabe.Unter_fenster()
        self.screen.show()
Im Unterfenster läuft der normale Dialog:

Code: Alles auswählen

if __name__ == '__main__':
    appe = QApplication(sys.argv)
    appe.setQuitOnLastWindowClosed(False)
    screen = Unter_fenster()
    screen.show()
    sys.exit(appe.exec_())
Wenn ich im Menü auf "Fenster schließen" gehe, sollte dies auch passieren...
Ein Versuch war:

Code: Alles auswählen

  
  appe.quit()
  
läuft aber auf den Hammer.

Ich muss wohl etwas an das Hauptfenster zurückgeben, damit dort das unter_fenster wieder geschlossen wird, nur wie?
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`appe` ist ein sehr komischer Name. Und den gibt es nur wenn das Modul als Programm ausgeführt wird, was es hier ja nicht wird. Das Fenster muss sich halt selbst schliessen. Fenster haben dafür eine `close()`-Methode. Die muss man mit dem Button/Menü oder was auch immer verbinden.

Wobei das hier auch nach generiertem Quelltext riecht — das macht man nicht mehr. Man lädt die `*.ui`-Datei zur Laufzeit des Programms statt daraus einen Modulquelltext zu generieren und zu importieren.

`Unter_fenster` sollte von der Schreibweise her `Unterfenster` heissen. Unterstriche in Klassennamen entsprechen weder Python- noch Qt-Konventionen. Wobei der Name extrem generisch ist. Das geht sicher inhaltlich treffender.

Auch `Daten_erfassen()` entspricht keiner der beiden Konventionen. Entweder `daten_erfassen()` oder `datenErfassen()`.

In der Methode wird nicht verhindert das mehr als ein Fenster auf diese Art geöffnet werden kann; das Attribut würde bei Folgeaufrufen überschrieben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
steenhy
User
Beiträge: 19
Registriert: Montag 23. März 2020, 20:22

Danke für die Hinweise.

Zu meinem Problem:

Code: Alles auswählen

def quit():
     screen.close()
     return
klappt nur, wenn das Fenster solo aufgerufen wird. Beim Start durch das Hauptfenster kommt der Hinweis, dass screen nicht vorhanden ist....

Die Zeile

Code: Alles auswählen

    appe.setQuitOnLastWindowClosed(False)
bitte vergessen, dies war nur ein Versuch aus einer anderen Lösung.
Sirius3
User
Beiträge: 17760
Registriert: Sonntag 21. Oktober 2012, 17:20

@steenhy: wo steht denn nun `quit`? Bitte zeigen vollständigen lauffähigen Code und welche exakte Fehlermeldung auftritt.
Benutzeravatar
sparrow
User
Beiträge: 4198
Registriert: Freitag 17. April 2009, 10:28

@steenhy: quit() sollte eine Methode innerhalb des Klasse des Fensters sein. Und das Fenster kennt sich selbst - und muss sich selbst schließen.
Wenn der Button nicht in dem Fenster, sondern in einem anderen Fenster ist, wird hoffentlich auch von dort das neue Fenster geöffnet. Und dort muss man sich den Verweis auf das neue Fenster merken.
steenhy
User
Beiträge: 19
Registriert: Montag 23. März 2020, 20:22

Vielen dank für die Infos!
Leider drücke ich mich nicht klar aus...
Also alles auf Anfang:
Ich habe zwei Dateien die jeweile ein Fenster steuern:
1.Datei: Hauptfenster.py:

Code: Alles auswählen

import sys
import Fenster_2
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QSize

class Window(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.init_ui()

    def init_ui(self):
        self.btn = QtWidgets.QPushButton("2.Fenster")
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.btn)
        self.setMinimumSize(QSize(100, 100))
        self.btn.clicked.connect(self.btn_clk)
        self.show()

    def btn_clk(self):
        screen = Fenster_2.Window2(self)
        screen.show()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    a_window = Window()
    sys.exit(app.exec_())
hier wird ein Fenster angezeigt, mit einem Bottom, dass ein zweites Fenster öffnet in:
2.Datei: Fenster_2.py:

Code: Alles auswählen

[import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QPushButton

class Window2(QMainWindow):
    def __init__(self, parent=None):
        super(Window2, self).__init__(parent)
        self.init_ui()

    def init_ui(self):
        self.btn= QPushButton('zu und zurück',self)
        self.btn.move(10,10)
        self.btn.clicked.connect(self.btn_clk)
   #     self.show()

    def btn_clk(self):
        a_window.close()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    a_window = Window2()
    sys.exit(app.exec_())

Wenn ich hier den Bottom "zu und zurück" drücke soll das auch passieren, es kommt die Meldung
File "U:\phyton\tbn\Fenster_2.py", line 17, in btn_clk
a_window.close()
NameError: name 'a_window' is not defined
Wenn ich das Fenster_2 solo starte, wird das Fenster ohne Fehlermeldung geschlossen.
Wer weiß weiter?
Benutzeravatar
sparrow
User
Beiträge: 4198
Registriert: Freitag 17. April 2009, 10:28

Auf Modulebene gehört kein Code außer die Abfrage um main() aufzurufen, Importe und die Deklaration von Funktionen, Klassen und Konstanten! Und wenn du das korrekt umsetzt, dann kommt es auch dann zu dem Fehler, wenn du deinen zweiten Code ausführst:

Code: Alles auswählen

import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QPushButton

class Window2(QMainWindow):
    def __init__(self, parent=None):
        super(Window2, self).__init__(parent)
        self.close_button= QPushButton('zu und zurück',self)
        self.close_button.move(10,10)
        self.close_buttonconnect(self.close_clicked)

    def close_clicked(self):
        window.close()

def main():
    app = QtWidgets.QApplication(sys.argv)
    window = Window2()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
Denn du hast unwissentlich deine Instanz von Window2 als globale Variable im Modul angelegt. Und globale Variablen möchte man nicht.

Also muss die Instanz von Window2 sich selbst schließen. Wie du auf die Instanz selbst zugreifst, weißt du ja. Machen die anderen Funktionen ja auch.
Warum gibt es eine __init__ und eine __init_ui? Die gehören beide in die __init__.
Wurden die automatisch generiert? Dann lies bitte den Hinweis von __blackjack__ weiter oben.
Es macht keinen Sinn die Klasse in ein extra Modul zu stecken.
Und bitte schreibe Namen aus. "btn_clk" klingt wie einer von diesen schlechten Sprüchen auf Shirts. Und Vokale essen weder Brot noch muss man ihnen mehr als den Mindestlohn zahlen. Deshalb darf man sie gerne verwenden um verständlichen Code zu schreiben.
steenhy
User
Beiträge: 19
Registriert: Montag 23. März 2020, 20:22

Danke für den Vorschlag.
Hat es bei Dir funktioniert?
Ich habe mir erlaubt die Zeile 10 zu korrigieren:

Code: Alles auswählen

       self.close_button.clicked.connect(self.close_clicked)
Dennoch bleibt bei es bei mir bei dem Fehler:
File "U:\phyton\tbn\Fenster_2.py", line 14, in close_clicked
window.close()
NameError: name 'window' is not defined
Benutzeravatar
sparrow
User
Beiträge: 4198
Registriert: Freitag 17. April 2009, 10:28

Ich habe deinen Fehler auch nicht korrigiert, sondern nur den Zufall behoben, dass die globale Variable versehentlich angesprochen wird.
Die Fehlermeldung ist ja recht aussagekräftig: Wo wird denn in der Klasse Window2 'window' definiert?
Du benutzt doch self sehr häufig, deshalb ging ich davon aus, dass du weißt, was self ist. self referenziert die aktuelle Instanz der Klasse. Wenn du also close() auf die eigene Instanz aufrufen möchtest, musst du self benutzen.
steenhy
User
Beiträge: 19
Registriert: Montag 23. März 2020, 20:22

Danke für den Zaunpfahl!
Die Lösung ist dann in Zeile 14:

Code: Alles auswählen

        self.close()
Dann ist plötzlich alles ganz logisch....

Was self ist, ist eine gute Frage. Ich habe da noch keine ordentliche Definition gefunden/verstanden.
Meine Erklärung ist, dass man mit self über mehre Ebenen auf eine Variable/Object zugreifen kann.
Bin offen für weitere Erklärungen.
Gibt es auch ein gutes Buch/tutorial zum Thema PyQt5 (z.b. wann QMainWindow und wann QtWidgets) ?
Ich bin noch bei Thonny müsste wohl mal auf Qt-Designer umsteigen oder was ist der nächste Schritt....

Danke für Eure Geduld und Hilfe!
Antworten