【问题标题】:how to show a modal QDialog without user interaction?如何在没有用户交互的情况下显示模态 QDialog?
【发布时间】:2019-06-20 09:37:32
【问题描述】:

我想展示一个不提供任何交互的无框模态对话框,甚至不提供关闭对话框的功能。我们的想法是打开对话框以显示一条长时间操作正在进行的消息警告,运行该操作,而不是关闭对话框。

qt 文档似乎表明可以在不执行其事件循环的情况下显示模式对话框:https://doc.qt.io/qt-5/qdialog.html#modal-dialogs

但是当我这样做时,对话框永远不会正确呈现在屏幕上。我得到一个黑色小部件,它的标签仍然不可见。

这是我的尝试:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class ModalInfoDialog(QDialog):
    """
    Frameless modal dialog with no interaction
    """

    def __init__(self, text1="Loading project",
                 text2="", parent=None):
        super().__init__(parent)
        self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint)
        self.setModal(True)
        self.setStyleSheet(
            """
            QDialog {
                background-color: white;
                border: none;
            }
            """)

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        firstLine = QLabel(text1)
        secondLine = QLabel(text2)

        layout.addWidget(firstLine)
        layout.addWidget(secondLine)


import time
app = QApplication([])

d = ModalInfoDialog("haha!", "huh?")
d.show()
QApplication.processEvents()  # does not help
time.sleep(3)
d.close()

【问题讨论】:

    标签: python pyqt pyqt5 qdialog


    【解决方案1】:

    您不必使用 processEvents,而是在另一个线程中实现任务,在这种情况下,我创建了一个 QObject,它存在于另一个线程中,并在任务结束时发出用于关闭窗口的信号。

    import time
    from PyQt5 import QtCore, QtWidgets
    
    
    class ModalInfoDialog(QtWidgets.QDialog):
        """
        Frameless modal dialog with no interaction
        """
    
        def __init__(self, text1="Loading project", text2="", parent=None):
            super().__init__(parent)
            self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
            self.setModal(True)
            self.setStyleSheet(
                """
                QDialog {
                    background-color: white;
                    border: none;
                }
                """
            )
    
            layout = QtWidgets.QVBoxLayout(self)
    
            firstLine = QtWidgets.QLabel(text1)
            secondLine = QtWidgets.QLabel(text2)
    
            layout.addWidget(firstLine)
            layout.addWidget(secondLine)
    
    
    class Worker(QtCore.QObject):
        finished = QtCore.pyqtSignal()
    
        @QtCore.pyqtSlot()
        def task(self):
            time.sleep(3)
            self.finished.emit()
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        d = ModalInfoDialog("haha!", "huh?")
        d.show()
        thread = QtCore.QThread(d)
        worker = Worker()
        worker.finished.connect(d.close)
        worker.moveToThread(thread)
        thread.started.connect(worker.task)
        thread.start()
        sys.exit(app.exec_())
    

    【讨论】:

    • 您的解决方案确实适用于我的简约示例,但在我的真实代码中它会导致段错误。我的长任务初始化并设置了一堆小部件,看来我不允许在单独的线程中这样做。我得想办法。
    • 不过,我将能够在我的程序的其他部分使用该解决方案,在这些部分中我无需接触 GUI 即可运行纯数据处理。
    • @PiRK 我的解决方案适用于您提供的 MRE,所以我认为我的回答是正确的(并且应该被接受),如果您的项目很复杂,这是一个无法解决的问题,在另一方面,您不应该直接从另一个更新 GUI,使用信号。
    猜你喜欢
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多