PyQT6 Fenster schließt sich immer

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Hirsch2001
User
Beiträge: 2
Registriert: Donnerstag 19. Mai 2022, 21:52

Moin,

ich bin gerade dabei mir eine Gui mit PyQT6 zu programmieren. Ich studiere Maschinenbau und muss im Rahmen eines Informatiklabors ein Sensor aus einem Auto auslesen und die Daten (Beschleunigung, Weg, etc.) mit einer Gui darstellen. An Vorwissen kann ich lediglich meine Informatik1 Veranstaltung vorweisen, dort haben wir aber nur Basics zu Phyton gelernt. Dinge wie die Socketprogrammierung oder den Umgang mit MySQL musste ich mir in den letzten 2 Monaten selbst beibringen. Mein Projekt für das Labor ist fast fertig, wenn ich nicht an der Gui scheitern würde.
Unzwar:
Ich habe in meinem Hauptfenster einen Pushbutton installiert, wenn ich diesen drücke soll sich ein 2., seperates Fenster öffnen. Die definierte Klasse für das 2. Fenster habe ich aus einem 2. Skript importiert. Das Fenster öffnet sich auch, verschwindet aber sofort wieder. Ich habe schon alles mir in den Sinn kommende probiert, komme aber nicht weiter und hoffe daher dass mir hier jemand helfen kann.

Grüße



Mein Hauptskript:
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QMainWindow
from PyQt6 import QtCore
import matplotlib.pyplot as plt
import matplotlib.lines as mlines


class Hauptfenster(QWidget): #(QWidget)

def __init__(self):
super(Hauptfenster, self).__init__()
self.initHaupt_Fenster()
self.setGeometry(50, 50, 500, 800)
self.setWindowTitle("Hauptfenster")
self.show()

def initHaupt_Fenster(self):
buttonGerade = QPushButton("Geradeausfahrt", self)
buttonGerade.move(50,50)
buttonGerade.clicked.connect(self.klicken)


def klicken (self):
print("Ich wurde gedrückt")
import GuI2
self.zweitesfenster = GuI2.Hauptfenster2()
self.zweitesfenster.show()



app = QApplication(sys.argv)
w = Hauptfenster()

sys.exit(app.exec())




Mein 2. Skript ("GuI2"):

from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QMainWindow
from PyQt6 import QtCore
import sys
import matplotlib.pyplot as plt
import matplotlib.lines as mlines

class Hauptfenster2(QWidget): #(QWidget)

def __init__(self):
super(Hauptfenster2, self).__init__()

self.setGeometry(50, 50, 500, 800)
self.setWindowTitle(" neues Hauptfenster")
self.plotten()
self.show

def plotten (self) :
blue_line = mlines.Line2D([], [], color='blue', marker='*',
markersize=15, label='Blue stars')
plt.legend(handles=[blue_line])
plt.show()

app = QApplication(sys.argv)

def main():

main = Hauptfenster2()
main.show()
sys.exit(app.exec())

main()
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Setze deinen Code hier bitte immer in Code-Tags. Die erscheinen automatisch, wenn du den </>-Button im vollständigen Editor drückst. Sonst gehen die Einrückungen verloren und die sind bei Python essentiell.

Import gehören an den Anfang eines Moduls, nicht irgendwo in irgenwelche Funktionen.

Es gehört nie ein Leerzeichen zwischen Namen und öffnende Klammer.

Auf Modulebene, also uneingerückt, dürfen nur die folgenden Dinge stehen: die Shabang, Importe, die Definition von Klassen, Funktionen und Konstanten und das Folgende. Mehr nicht. Dein Programm gehört komplett in eine Funktion "main" die wie folgt am Ende des Scripts aufgerufen wird:

Code: Alles auswählen

if __name__ == "__main__":
    main()
Das verhindert, das beim Import eines Moduls main aufgerufen wird. Das ist wahrscheinlich, was dir hier auf die Füße fällt. Und dass du auf Modulebene "app" hast. Das gehört da auch nicht hin. Es darf in einem PyQT-Programm nur eine QApplication geben.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Die `initHaupt_Fenster` sollte nicht existieren, weil alles in __init__ initialisiert wird. Methoden schreibt man wie Variablennamen komplett klein. Der Unterstrich ist auch irgendwie an der falschen Stelle, so muß ich rätseln, was ein initHaupt ist.
Alle Attribute müssen bereits in __init__ angelegt werden, so auch zweitesfenster; der Wert kann None sein.

Das Hauptfenster ist per Definition das einzige Hauptfenster. Wie kann es da ein Hauptfenster2 geben?

Im ganze Programm darf es nur eine Instanz von QApplication geben, Du erzeugst aber zwei davon, was dann zu ganz komischem Verhalten führen kann.

Ein ´self.show` ohne dass man es aufruft, ist Unsinn. show in __init__ aufzurufen ist auch Unsinn, weil der Aufrufer entscheidet, wann das Fenster angezeigt wird; die Zeilen müssen so oder so weg.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hirsch2001: Im ersten Modul werden Sachen aus `matplotlib` importiert die nicht verwendet werden.

`QMainWindow` wird importiert und nicht verwendet.

`super()` ruft man ohne Argumente auf.

Namen sollten nicht aus kryptischen Abkürzungen oder gar nur einem Buchstaben bestehen und auch nicht nummeriert werden. Kein Leser will wissen, dass es sich um die zweite GUI oder das zweite Fenster handelt, sondern was die Bedeutung von diesen Werten ist. Also beispielsweise `PlotFenster` wenn das einen Plot darstellen soll. Vielleicht auch im Namen vermitteln was dieser Plot für eine Bedeutung hat.

Wenn das Fenster an ein Attribut gebunden wird, sollte man vorher prüfen ob da nicht schon ein Fenster an dieses Attribut gebunden ist, dass man dann ersetzen würde, und entsprechend reagieren. Oder man lässt das binden an ein Attribut weg.

Eine Klasse pro Datei ist ein „code smell“. Das ist Python und nicht Java. Wobei `Hauptfenster2` in der Form auch simpel genug ist, dass es nicht einmal eine eigene Klasse sein muss.

`setGeometry()` und auch `move()` haben da eigentlich nichts zu suchen. Fenster die meinen besser zu wissen wo sie angezeigt werden als die Fensterverwaltung sind die Pest. Die Grösse ergibt sich aus dem Inhalt und nicht durch eine feste Vorgabe in der Hoffnung das alles rein passen wird und auch nicht zu viel leerer Platz bleibt.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import sys

import matplotlib.lines as mlines
import matplotlib.pyplot as plt
from PyQt6.QtCore import QEvent
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget


class Hauptfenster(QWidget):
    def __init__(self):
        super().__init__(windowTitle="Hauptfenster")
        self.fenster = None
        layout = QHBoxLayout()
        layout.addWidget(
            QPushButton("Geradeausfahrt", self, clicked=self.on_button)
        )
        self.setLayout(layout)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Close:
            self.fenster = None
            return True
        else:
            return super().eventFilter(obj, event)

    def on_button(self):
        print("Ich wurde gedrückt")
        if not self.fenster:
            self.fenster = QWidget(windowTitle="neues Fenster")
            self.fenster.installEventFilter(self)
            self.fenster.show()

            blue_line = mlines.Line2D(
                [],
                [],
                color="blue",
                marker="*",
                markersize=15,
                label="Blue stars",
            )
            plt.legend(handles=[blue_line])
            plt.show()


def main():
    app = QApplication(sys.argv)
    fenster = Hauptfenster()
    fenster.show()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Hirsch2001
User
Beiträge: 2
Registriert: Donnerstag 19. Mai 2022, 21:52

Moin,

habt vielen Dank für euere Hilfe.
Wenn ich jetzt weitere Buttons mit dahintergeschalteten Fenster "haben" möchte, kann ich dann die entsprechenden Codezeilen einfach vervielfältigen oder gibt es etwas was ich (noch) nicht auf dem Schirm habe das ebendies nicht gehen würde?
Hintergrund des ganzen ist, dass dort in Zukunft verschiedene Diagramme geplottet werden sollten, z.B. ein für Beschleunigungswerte oder eins für die dort wirkende Kraft. Die Diagramme sollen über die Buttons gewählt werden.

@_blackjack_ Dein Skript funktioniert, mein Programm sagt mir aber das "Close" bei QEvent nicht definiert ist.
Und ich wollte nochmal Fragen, ob du mir folgene Zeilen nochmal erläutern kannst, weil mein bisheriges Wissen nicht ganz ausreicht um mir das lückenlos zu erklären:

Code: Alles auswählen

def eventFilter(self, obj, event):
        if event.type() == QEvent.Close:
            self.fenster = None
            return True
        else:
            return super().eventFilter(obj, event)



Anbei: Weiß jemand wie ich es schaffe, dass mein Plot von Matlib in dem Fenster und nicht in meiner Programmierumgebung geschieht? Bzw. weiß jemand wo ich etwas dazu finden was mir die Frage beantworten kann?


Vielen Dank und ein schönes Wochende
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hirsch2001: Der `eventFilter` ist nötig um mitzubekommen, dass das Fenster geschlossen wird, denn man muss ja verhindern, dass ein weiteres Fenster geöffnet wird solange das Fenster noch offen ist, um das Attribut wieder auf `None` setzen zu können.

Ich habe kein PyQt6 hier installiert, darum konnte ich das nur mit PyQt5 testen. Wahrscheinlich wurde die Konstante in einen anderen Namensraum verschoben in PyQt6. Die Dokumentation weiss da sicher mehr.

Wenn die Programmierumgebung irgendwelche Probleme macht, beziehungsweise selbst wenn sie das nicht macht, würde ich Programme immer ausserhalb starten, so wie das letztlich dann ja produktiv auch passieren wird.

Ansonsten verstehe ich die Frage auch nicht so ganz. Im Moment hast du ja drei Fenster: Das Hauptfenster, dein zweites Fenster, und dann das Fenster das von `plt.show()` erstellt wird. Willst Du dann eventuell einfach Dein zweites Fenster weg lassen? Oder den Plot in ein Qt-Fenster integrieren? Letzteres steht in der `matplotlib`-Dokumentation. Da gibt es auch Beispiele in der Gallerie für verschiedene GUI-Rahmenwerke.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten