Dialog vor Fenster aber nicht vor anderen Anwendungen anzeigen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

Hallo!

Ich nutze Pyside6 und QTDesigner.

Ich möchte aus meiner Anwendung heraus einen QDialog starten, der vor dem Hauptfenster sichtbar bleibt, aber nicht vor anderen Anwendungen. Alles was ich bisher ausprobiert habe führt entweder dazu, dass der Dialog auch vor allen anderen Anwendungen angezeigt wird, die sich allerdings zwischen Hauptfenster und Dialog schieben, oder dass der Dialog auch hinter dem Hauptfenster verschwindet.

Der Dialog bleibt auch immer modal, egal was in den Eigenschaften in QTDesigner oder im Code eingestellt wurde und egal ob ich ihn mit exec oder show öffne (was momentan kein großes Problem ist, da ich diese Funktion wünsche, aber den Dialog in Zukunft eventuell auch nicht modal haben möchte).

Kann mir da jemand weiterhelfen?
Benutzeravatar
__blackjack__
User
Beiträge: 13130
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tanrim: Ich würde sagen hier verlässt Du den Bereich dessen was ein GUI-Rahmenwerk leisten kann, denn das fällt in den Aufgabenbereich der Fensterverwaltung vom System. So ganz allgemein können Anwendungen da sowieso nur Vorschläge machen, die der Fenstermanager dann umsetzt oder eben auch nicht. Das kann sich von Fenstermanager zu Fenstermanager unterscheiden, und zumindest unter Linux kann man da manchmal auch sehr viel konfigurieren.

Was ist denn der Einsatzzweck?
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

Ich möchte eigentlich nur (meines Wissens nach) Standardverhalten. Als Beispiel:

Ich habe das Hauptfenster meiner Anwendung, das einen Einstellungen-Dialog aufruft, der vor dem Hauptfenster zu sehen sein soll, aber nicht vor allen anderen Anwendungen.

Wenn Hauptfenster/Dialog minimiert sind und ich beispielsweise über die Taskleiste die Anwendung wieder in den Fokus bringe, sollen Hauptfenster und Dialog gemeinsam vor den anderen Anwendungen sichtbar sein.

So wie es eben in fast jeder Anwendung der Fall ist, mir hier aber nicht gelingt.

Bei mir ist es so, dass der Dialog nicht nur vor dem Hauptfenster erscheint, sondern vor allen Anwendungen. Und wenn ich den Dialog über die Taskleiste aufrufe, erscheint nicht das Hauptfenster. Oder auch: Wenn ich den Dialog gestartet habe und auf eine andere Anwendung klicke, schiebt sich diese vor das Hauptfenster hinter den Dialog.
Benutzeravatar
sparrow
User
Beiträge: 4201
Registriert: Freitag 17. April 2009, 10:28

Poste bitte ein kurzes, ausführbaren Beispiel, das dein Problem zeigt.
Benutzeravatar
__blackjack__
User
Beiträge: 13130
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tanrim: Das kenne ich so nicht als Standardverhalten. Auf welchem System ist das denn?
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

Code: Alles auswählen

import sys

from PySide6.QtCore import Qt
from PySide6 import QtWidgets as qtw


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(800, 600)


class Ui_DialogEinstellungen(object):
    def setupUi(self, DialogEinstellungen):
        if not DialogEinstellungen.objectName():
            DialogEinstellungen.setObjectName(u"DialogEinstellungen")
        DialogEinstellungen.resize(400, 300)


class HauptFenster(qtw.QMainWindow, Ui_MainWindow):

    def __init__(self):
        super().__init__()
        self.setupUi(self)

    def mouseReleaseEvent(self, event):

        dialog = DialogEinstellungen()

        if event.button() == Qt.LeftButton:

            dialog.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)

        dialog.exec()


class DialogEinstellungen(qtw.QDialog, Ui_DialogEinstellungen):

    def __init__(self):

        super().__init__()

        self.setupUi(self)


if __name__ == "__main__":

    app = qtw.QApplication(sys.argv)

    window = HauptFenster()
    window.show()

    app.exec()
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

@__blackjack__:

Windows 10

Kann ich mir fast nur vorstellen, dass wir uns missverstehen.
Ziemlich jedes Programm, dass ich auf die schnelle vergleichbar finde, verhält sich so:

Windows Explorer(!), Pycharm(!), QTDesigner(!), Notepad++, IrfanView, Mp3tag, LibreOffice, DirectoryOpus,...

Bei manchen ist der Dialog in der Taskleiste nicht als eigenes Fenster sichtbar, das würde mir auch entgegenkommen.
Benutzeravatar
sparrow
User
Beiträge: 4201
Registriert: Freitag 17. April 2009, 10:28

@Tanrim: Woher weiß dein Dialog zu welchem Fenster er gehört? Also wer das 'parent' ist?
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

Danke für den Hinweis. Ich hatte das zwischendurch auch drin, was aber keine sichtbare Veränderung gebracht hatte, zumindest nicht dort, wo ich mit meiner Aufmerksamkeit war.

Tatsächlich wird jetzt aber nur ein Fenster in der Taskleiste angezeigt und das Hauptfenster gemeinsam mit dem Dialog wieder nach vorne gebracht.
Allerdings bleibt das Problem, dass der Dialog vor allen anderen Anwendungen erscheint und diese sich auch zwischen Hauptfenster und Dialog schieben, wenn bei geöffnetem Dialog eine Anwendung neben dem Hauptfenster angeklickt wird.

Wie kann ich meinen Code denn ändern, dass der Dialog nur vor dem Hauptfenster liegt?

Code: Alles auswählen

dialog.setParent(self)
dialog.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

Ok, habs rausgefunden:

Code: Alles auswählen

dialog.setWindowFlags(Qt.Window)
Vielen Dank für die richtige Fährte. War der zwischendurch zwar auch nachgegangen, das hatte aber nicht funktioniert und diese einfache Lösung hab ich auch trotz langen Suchens nicht gefunden.

Super, funktioniert jetzt alles so, wie ich mir das vorstelle! Danke!
Benutzeravatar
sparrow
User
Beiträge: 4201
Registriert: Freitag 17. April 2009, 10:28

Du mchst in deinem Code sehr viele Dinge sehr umständlich bis falsch.

Dieses sehr simple Beispiel (ohne dieses Erben von mehreren Klassen, das vollkommen unnötig ist) bildes das ganz Standardverhalten ab, wie ich es kenne:

Code: Alles auswählen

import sys

from PySide6.QtCore import Qt
from PySide6 import QtWidgets as qtw


class HauptFenster(qtw.QMainWindow):

    def __init__(self):
        super().__init__()
        self.resize(800, 600)

    def mouseReleaseEvent(self, event):
        dialog = DialogEinstellungen(self)
        dialog.exec()


class DialogEinstellungen(qtw.QDialog):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.resize(400, 300)


if __name__ == "__main__":

    app = qtw.QApplication(sys.argv)

    window = HauptFenster()
    window.show()

    app.exec()
Benutzeravatar
__blackjack__
User
Beiträge: 13130
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tanrim: Das ist ein bischen redundant, denn Qt.Window ist in Qt.Dialog enthalten:

Code: Alles auswählen

In [17]: (Qt.Window | Qt.Dialog) == Qt.Dialog
Out[17]: True
Und Qt.Dialog ist bei QDialog natürlich sowieso schon gesetzt. Das ist ja *das* Flag für einen *Dialog*.

Ich vermute mal stark der Fehler ist `setParent()` zu verwenden statt das gleich beim erstellen anzugeben wie man das ja normalerweise macht.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

@sparrow:

Wie ich in meinem ersten Beitrag geschrieben habe, nutze ich QTDesigner.

Ich habe ein ziemlich aufwendiges GUI und kompiliere die QTDesigner-Dateien in py, die ich aber nicht verändere, weil ich sonst jedesmal wenn ich das GUI verändere den Code anpassen müsste.

Das heißt obiger Code sind eigentlich vier unterschiedliche Module zusammengefasst.


@__blackjack__:

Nicht so ganz, denn ich habe mit Dialogen angefangen, die mittlerweile aber eher Fenster geworden sind. Ohne < dialog.setWindowFlags(Qt.Window) > wird der Maximieren-Button nicht angezeigt.


Ich habe den Code jetzt nochmal angepasst und ein Beispiel für Einstellungen als QDialog und eines als QMainWindow.

Funktioniert so beides identisch und einwandfrei.

So jetzt in Ordnung?

Code: Alles auswählen

import sys

from PySide6.QtCore import Qt
from PySide6 import QtWidgets as qtw


# Generiert von QTDesigner und in unverändertes Modul kompiliert.
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(800, 600)

# Generiert von QTDesigner und in unverändertes Modul kompiliert.
class Ui_DialogEinstellungen(object):
    def setupUi(self, DialogEinstellungen):
        if not DialogEinstellungen.objectName():
            DialogEinstellungen.setObjectName(u"DialogEinstellungen")
        DialogEinstellungen.resize(400, 300)

# Main
class HauptFenster(qtw.QMainWindow, Ui_MainWindow):

    def __init__(self):
        super().__init__()
        self.setupUi(self)

    def mouseReleaseEvent(self, event):

        if event.button() == Qt.LeftButton:

            dialog = DialogEinstellungen(self)

            dialog.setWindowFlags(Qt.Dialog | Qt.WindowMaximizeButtonHint | Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint)

            dialog.exec()

        else:

            dialog = FensterEinstellungen(self)

            dialog.setWindowModality(Qt.WindowModal)

            dialog.show()


# Modul Einstellungen
class FensterEinstellungen(qtw.QMainWindow, Ui_MainWindow):

    def __init__(self, parent):
    
        super().__init__(parent)
        
        self.setupUi(self)
        
        self.resize(400, 300)


class DialogEinstellungen(qtw.QDialog, Ui_DialogEinstellungen):

    def __init__(self, parent):

        super().__init__(parent)

        self.setupUi(self)


if __name__ == "__main__":

    app = qtw.QApplication(sys.argv)

    window = HauptFenster()
    
    window.show()

    app.exec()
Benutzeravatar
sparrow
User
Beiträge: 4201
Registriert: Freitag 17. April 2009, 10:28

@Tanrim: Den Umweg über die generierte .py Dateien macht man seit Jahren nicht mehr. Man lädt die .ui Dateien direkt. Such mal "QUiLoader". Das macht dann acuh dieses erben von 2 Klassen unnötig. - und dieses seltsame Setzen von Klassenattributten.
Und ich persönlich würde das setzen der Flags für den Dialog eher in der Initialisierung der Dialog-Instanz setzen und nicht hinterher setzen.
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

sparrow hat geschrieben: Samstag 20. April 2024, 16:48 @Tanrim: Den Umweg über die generierte .py Dateien macht man seit Jahren nicht mehr. Man lädt die .ui Dateien direkt. Such mal "QUiLoader". Das macht dann acuh dieses erben von 2 Klassen unnötig. - und dieses seltsame Setzen von Klassenattributten.
Und ich persönlich würde das setzen der Flags für den Dialog eher in der Initialisierung der Dialog-Instanz setzen und nicht hinterher setzen.
Ok, danke für den Tip!
Benutzeravatar
__blackjack__
User
Beiträge: 13130
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tanrim: Das Problem mit dem harten Setzen ist das die Defaultwerte für verschiedene Systeme unterschiedlich sein können. Ich habe hier unter KDE beispielsweise Maximieren und Minimieren auch ohne irgendwas setzen zu müssen. Und wenn man die Dokumentation anschaut gibt es ein `setSizeGripEnabled()` das man setzen kann — vielleicht gibt das unter Windows dann auch diese Buttons in der Titelzeile‽ Auf jeden Fall würde ich den alten Wert als Grundlage nehmen und den nicht einfach überschreiben. Das spräche dafür die Flags erst hinterher zu setzen.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Tanrim
User
Beiträge: 14
Registriert: Montag 11. März 2024, 12:20

__blackjack__ hat geschrieben: Samstag 20. April 2024, 17:27 @Tanrim: Das Problem mit dem harten Setzen ist das die Defaultwerte für verschiedene Systeme unterschiedlich sein können. Ich habe hier unter KDE beispielsweise Maximieren und Minimieren auch ohne irgendwas setzen zu müssen. Und wenn man die Dokumentation anschaut gibt es ein `setSizeGripEnabled()` das man setzen kann — vielleicht gibt das unter Windows dann auch diese Buttons in der Titelzeile‽ Auf jeden Fall würde ich den alten Wert als Grundlage nehmen und den nicht einfach überschreiben. Das spräche dafür die Flags erst hinterher zu setzen.
Das ist gut zu wissen, danke!

`setSizeGripEnabled()` war schon aktiviert.
Antworten