zweites Fenster öffnen - mit loadUi

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Hallo Zusammen,

ich habe die Suchfunktion durchforstet aber bin auf kein finales Ergebnis gestoßen, viele Leute standen wohl vor dem selben Problem aber eine Lösung habe ich in keinen der Threads gefunden.
Wie der Titel bereits sagt, möchte ich, ein weiteres Fenster öffnen, doch wie mache ich das?

Ich bin im Netz auf folgendes Video gestoßen: https://www.youtube.com/watch?v=82v2ZR-g6wY&t=139s
Meine Frage, würdet ihr den selben Weg gehen oder einen anderen?

Eine zusätzliche Frage, macht es was aus wenn ich nur mit QDialog Fenster arbeite? oder sollte man mit MainWindow und entsprechenden QDialogs arbeiten? Final werde ich 4 Fenster haben (1. Login-Fesnter, 2. Passwort vergessen Fenster, 3. Bentuzer erstellen Fenster, 4. Übersicht von Kennzahlen die aus Login-Namen resultieren.
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Das hat ja erst einmal nichts mit loadUI zu tun.
Wenn du ein weiteres Fenster möchtest, dann ist das ja eine Klasse des entsprechenden "Containers". Wenn du also ein QWidget im Designer erstellst, das als entsprechende Klasse (mit loadUI in der __init__) im Programm hast und die dann entsprechend instanzierst, reicht eineinfasches .show() auf der Instanz um das zweite Fenster anzeigen zu lassen.

Zur zweiten Frage:
In der Regel hat man ein MainWindow - weil Desktop-Applikationen in der Regel so funktionieren, dass sie ein zentrales Fenster haben. Ein QDialog ist ein bisschen eingeschränkt und ich verwende den, wenn es wirklich nur ein minimales Bestätigungsfenster ist. Alles was darüber hinaus geht, leite ich von einem QWidget ab.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich denke für Passwort eingeben/vergessen/Benutzer erstellen, kann man auch Dialoge verwenden, eventuell auch das davon abgeleitete `QWizard` falls beispielsweise Benutzer anlegen so viele Eingaben benötigt, dass es unübersichtlich wird, oder wenn der Vorgang in Schritten durchgeführt werden muss.

Die Frage nach dem `QMainWindow` beantwortet sich ja im Grunde selbst wenn `QWidget` etwas nicht bietet was `QMainWindow` hat. Also Menü oder Statusbar beispielweise würde ich mir nicht in ein `QWidget` basteln.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Hey, vielen Dank für eure Antworten.
Habt ihr vielleicht ein Code-Beispiel um ein zweites Fenster zu öffnen, mit einer kurzen Erklärung?
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Ich habe gerade, das probiert, was leider auch nicht funktioniert, wahrscheinlich weil nur eine app gleichzeitig laufen kann.

Code: Alles auswählen

from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QLineEdit, QShortcut, QDialog
from PyQt5.QtGui import QKeySequence
from PyQt5 import uic
import sys


class GUI(QMainWindow):
    def __init__(self):
        super(GUI, self).__init__()

        # Lade die .ui Datei
        uic.loadUi("willkommen.ui", self)
        # Setzte das Fenster im Fullscreen Modus
        self.showFullScreen()
        # Definiere einen Shortcut um das Fenster in die Maximized Modus zu setzten
        self.maxiMode = QShortcut(QKeySequence("Ctrl+Q"), self)
        self.maxiMode.activated.connect(self.showMaximized)

        self.button_Login.clicked.connect(self.openCreateUserWindow)

    def openCreateUserWindow(self):
        app2 = QApplication(sys.argv)
        CreateUserWindow = GUICreateUser()
        CreateUserWindow.show()
        app2.exec_()

class GUICreateUser(QDialog):
    def __init__(self):
        super(GUICreateUser, self).__init__()
        uic.loadUi("bentuzererstellen.ui", self)

# Initialisiere/starte die App
app = QApplication(sys.argv)
GUIWindow = GUI()
GUIWindow.show()
app.exec_()
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Ich werde gerade einfach nicht schlau, im Netz gibt es so viele verschiedene Möglichkeiten jedoch finde ich keine passende für mich, auch in diesem Tutorial wird der Weg beschrieben: https://www.youtube.com/watch?v=R5N8TA0KFxc aber das klappt nicht bei mir. Dort im Video wandelt er die .ui Dateien in .py Dateien um import die und greift dann auf setup.ui zu. Das kann ich nach loadUi nicht, ich kann zwar die Ui Klasse mit loadUi mit in den Code schreiben aber was ich anstelle von self.ui.setupUi machen soll das weiß ich nicht.

Wäre euch super dankbar für Lösungsvorschläge :)
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Crypto-Alman: Es kann in der Tat nur ein `QApplication`-Objekt geben das *die* Anwendung repräsentiert.

Da es sich offensichtlich um einen QDialog handelt, würde sich hier die `exec()`-Methode anbieten, was gleichzeitig den netten Effekt hat, dass der Aufruf blockiert und man sich keine Gedanken darüber machen muss, was eigentlich passiert wenn der Benutzer den Button mehfach drückt.

Anmerkungen zum Quelltext: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

`super()` braucht keine Argumente. Das ist Python 2 und man kann das in Python 3 noch machen, damit sich alter Code einfacher portieren lässt, aber in neuem Code macht es keinen Sinn und ist eine unnötige Fehlerquelle.

Es macht keinen Sinn irgendwelche Nummern an Namen zu hängen.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import sys

from PyQt5 import uic
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QShortcut


class GUICreateUser(QDialog):
    def __init__(self, parent):
        super().__init__(parent)
        uic.loadUi("bentuzererstellen.ui", self)


class GUI(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("willkommen.ui", self)
        self.showFullScreen()
        QShortcut(QKeySequence("Ctrl+Q"), self, activated=self.showMaximized)
        self.button_Login.clicked.connect(self.openCreateUserWindow)

    def openCreateUserWindow(self):
        GUICreateUser(self).exec()


def main():
    app = QApplication(sys.argv)
    gui = GUI()
    gui.show()
    app.exec()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Ich nochmal, also ich bekomme es nur hin, wenn ich ein QWidget erstelle, wenn ich ein QDialog oder gar ein QMainWindow nehme klappt es nicht.
Grundsätzlich habe ich damit kein Problem mit dem QWidget weiterzuarbeiten, gibt es erwähnenswerte Unterschiede zwischen den beiden? Kann ich Beispielsweise mein Willkommensbildschrim als MainWindow und Passwort vergessen, Bentuzer erstellen und die Datenübersicht als QWidget beibehalten?

Code: Alles auswählen

from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QLineEdit, QShortcut, QDialog, QWidget
from PyQt5.QtGui import QKeySequence
from PyQt5 import uic, QtWidgets, QtCore
import sys


class GUI(QMainWindow):
    def __init__(self):
        super(GUI, self).__init__()

        # Lade die .ui Datei
        uic.loadUi("willkommen.ui", self)
        # Setzte das Fenster im Fullscreen Modus
        self.showFullScreen()
        # Definiere einen Shortcut um das Fenster in die Maximized Modus zu setzten
        self.maxiMode = QShortcut(QKeySequence("Ctrl+Q"), self)
        self.maxiMode.activated.connect(self.showMaximized)

        self.button_Login.clicked.connect(self.openCreateUserWindow)

    def openCreateUserWindow(self):
        self.CreateUserWindow = GUICreateUser()
        self.CreateUserWindow.show()


class GUICreateUser(QWidget):
    def __init__(self):
        super(GUICreateUser, self).__init__()
        uic.loadUi("test.ui", self)
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

@__blackjack__ Vielen Dank für deine Hilfe und die Tipps, da hat sich meine Antwort mit deiner überschnitten sorry, ich habe deinen Lösungsvorschlag getestet und er funktioniert sowohl mit QDíalog als auch mit QWidget. Ich denke dann arbeite ich jetzt damit weiter. Habe ich denn große Einschränkung wenn ich mit einen der beiden weiterarbeite?

Und noch eine weitere Frage, wenn ich dann das dritte Fenster hinzu nehme, muss ich dann hinter parent eine Zahl setzten oder macht das auch keinen Sinn? Habe nur dran gedacht das es sich vielleicht überschneidet.

Code: Alles auswählen

class GUICreateUser(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        uic.loadUi("test.ui", self)
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Crypto-Alman: QWidget ist halt ein ”nacktes” Fenster und Grundlage für alles weitere und QDialog bringt noch verhalten für Dialoge dazu was man sich sonst selbst programmieren müsste.

Edit: Die Frage nach einer Zahl verstehe ich nicht wirklich. Zahlen an Namen anzuhängen ist im Grund immer ein Hinweis auf was komisches oder das Namensräume nicht verstanden wurden. Mit was soll `parent` sich denn hier überschneiden?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

@__blackjack__ hast du ein Beispiel was bei einem QWidget hinzuprogrammiert werden müssten im Vergleich zu einem Dialog? Sorry für meine vielen Fragen.

Ehrlich gesagt, dachte ich mir parent steht für paar also für das zweite Fenster, ich bin davon ausgegangen das ich dann jeder Funktion einen anderen parent zuweisen muss. Dadurch das ich aber immernur auf einen gleichzeitig zugreife brauche ich nie Zahlen dahinter setzen, richtig? :)
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Ich habe noch eine weitere Frage, vorher als ich noch in den .py Dateien gearbeitet habe, habe ich mir ein "Klickbares Label" erstellt.
Ich habe folgendes Modul im Netz gefunden und habe dann anstelle das Qwidgets.QLabel auszuwählen das Modul importiert und an der Stelle das anklickbare Label angestuert.

Code: Alles auswählen

from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QMessageBox


class QLabelClickable(QLabel):
    clicked = pyqtSignal(str)

    def __init__(self, parent=None):
        super(QLabelClickable, self).__init__(parent)

    def mousePressEvent(self, event):
        self.ultimo = "Click"

    def mouseReleaseEvent(self, event):
        if self.ultimo == "Clic":
            QTimer.singleShot(QApplication.instance().doubleClickInterval(),
                              self.performSingleClickAction)
        else:
            # Realizar acción de doble clic.
            self.clicked.emit(self.ultimo)
Kann ich trotzdessen ich die ui lade, noch manuell Widgets in diesem Fenster platzieren? Oder wie kann ich hier am besten vorgehen?
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Crypto-Alman: Das mit dem `parent` verstehe ich nicht. Funktionen musst Du da gar nichts zuweisen. `parent` ist ein Argument der `__init__()`-Methode und wie bei allen Argumenten von Funktionen und Methoden ist das ein lokaler Name der nur innerhalb der Funktion oder Methode sichtbar ist.

Der Wert dahinter steht hier für das `QObject`-Objekt das als Elternelement im Objektbaum verwendet wird. Das ist ein sehr grundlegendes Konzept von Qt das in Qt's Basisobjekt `QObject` schon implementiert ist, das `QObject`-Objekte ein Eltern-`QObject` haben können und selber dementsprechend Kinderobjekte. Beides kann man auch von jedem `QObject` mit `parent()` und `children()` abfragen und es wird von Qt für die Speicherverwaltung verwendet. Da muss man an bestimmten Stellen in Python dann aufpassen, weil auf Python-Seite Objekte verschwinden wenn die in Python nicht mehr erreichbar sind. Das einzige was `QObject`-Objekte daran hindern kann dann einfach gelöscht zu werden, ist das sie auf Qt-Seite in einem Objektbaum stecken auf den man irgendwie noch von Python aus zugreifen kann.

Ein bisschen was zu `QDialog`-Unterschieden zu `QWidget` steht in der Dokumentation von `QDialog`. Es kann auch sein, dass es plattformabhängige Unterschiede gibt, weil da ja oft Richtlinien von den Herstellern existieren und der Benutzer erwartet das sich Anwendungen auf der Plattform möglichst gleich verhalten.

Man kann mit dem was `loadUi()` liefert alles machen was man auch mit einem solchen Objekt machen kann was man manuell erstellt hat, also auch nachräglich noch Elemente hinzufügen. Ich würde bei solchen Sachen eber eher ein `QLabel` was man mit dem Designer da gesetzt hat nachträglich durch einen Eventfilter (`QObject.installEventFilter()`) realisieren.

Wozu brauchst Du das denn? Kannst Du nicht einfach einen Link auf einem `QLabel` darstellen? Oder einen `QPushButton` der ”flat” dargestellt wird?

Ich würde vorsichtig sein damit neue Bedienelemente zu erfinden die Benutzer nicht gewohnt sind. Links und Buttons kennt der Benutzer, da weiss er, dass er drauf klicken kann. Wenn man neue klickbare Elemente ”erfindet” muss man dafür sorgen, dass der Benutzer auch irgendwie mitbekommt, wie man die benutzt, unter Umständen das sie überhaupt da sind.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Guten Morgen Zusammen,

vielen Dank für die Antwort und die Erklärung.
Parent und Objektbaum habe ich verstanden und zu den Unterschieden QDialog und QWidget habe ich bisschen nachgelesen, nichts "gravierendes" gefunden.

Nochmal zu meinem Label zurück, ich möchte das unter dem Eingabefeld Passwort ein unterstrichenes Label steht mit Passwort vergessen?.. so finde ich es schön und kenne es auch von dem ein oder anderen Interface. Kann ein Link auf einem QLabel auch eine Funktion sein die dann das Passwort vergessen Fenster öffnet?

Bezüglich ändern der von loadUi geladenen Elemente, muss ich dann in dem main file in dem ich die Ui lade "einfach" ein Widget platzieren oder greife ich mit findchild auf das bestehende Label zu und ändere dies zu einem clickable Label? Kenne mich mti Evenfilter leider noch nicht aus.
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was du beschreibst ist das Verhalten einer Webseite. Wenn Du das willst, dann bau doch eine Webseite.

Das Labels Hyperlinks unterstützen steht hier: https://doc.qt.io/qt-5/qlabel.html#open ... Links-prop

Die dann aber abzufangen, oder eine beliebige Interaktion daran zu binden, ist nicht vorgesehen. Du programmierst hier also gegen das Framework.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@__deets__: Die Links lösen beim Klick doch ein linkActivated-Signal aus. Da kann man dann doch irgend etwas beliebiges machen.

@Crypto-Alman: Ja, das sollte gehen.

Re „clickable Label“: Wozu `findChild()`? Wenn Du dem Label einen Namen gegeben hast, kannst Du doch einfach über diesen Namen als Attribut auf das Label zugreifen. Wie Du das ja bei `self.button_Login` für den Button auch gemacht hast. Und dann kannst Du mit `installEventFilter()` ein `QObject` mit der passenden Methode registrieren. Ist aber umständlicher als einfach einen Link auf dem `QLabel` anzuzeigen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

__blackjack__ hat geschrieben: Freitag 27. Mai 2022, 14:28 @__deets__: Die Links lösen beim Klick doch ein linkActivated-Signal aus. Da kann man dann doch irgend etwas beliebiges machen.
Ups. Das habe ich uebersehen.
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Hey Zusammen,

vielen Dank für eure Hilfe, kannst du mir das genauer erklären? Ich bekomme die Vorgehensweise gerade nicht in den Kopf bzw. kenne die Möglichkeit über installEventFilter() nicht.
Ich gehe jetzt her, und lade die Ui und greife dann auf das QLabel zu und installiere einen EventFilter um es anschließend anklickbar zu machen?
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Crypto-Alman: Wenn Du einen Link haben willst, warum benutzt Du dann nicht einfach die Möglichkeit einen Link auf dem Label anzuzeigen? Das kann `QLabel` von Haus aus, da muss man nichts selber programmieren. Nur das `linkActivated`-Signal mit einem entsprechenden Slot verbinden, im Grunde so wie man das mit dem `clicked`-Signal von einem Button machen würde. Unterschied: das `linkActivated`-Signal hat eine Zeichenkette als Argument, welches das Linkziel übermittelt, damit man in der Lage ist mehrere Links in dem Label auseinander zu halten. Wenn man nur einen Link da rein packt, kann man den Wert dann einfach ignorieren.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Crypto-Alman
User
Beiträge: 34
Registriert: Montag 23. Mai 2022, 20:26

Beim klicken auf das Label soll das Fenster Passwort vergessen geöffnet werden kein Link, kann ich das trotzdem nutzen?
Antworten