PyQt5-如何在showEvent中关闭模式对话框?

问题描述 投票:0回答:1

我不敢相信我必须问这个问题,但是我无法从showEvent中关闭PyQt5模态对话框。

这里是演示该问题的微型示例程序。该测试程序的预期行为是因为设置了somethingWentTerriblyWrong,一旦按下btnShowDialog,模态对话框也许应该显示一瞬间(即使持续很长时间),然后自动关闭,但是您可以从中看到下面的屏幕截图不会发生。

# test.py

from PyQt5.QtWidgets import QApplication, QDialog, QWidget, QLabel, QGridLayout, QPushButton
from PyQt5.Qt import Qt

def main():
    app = QApplication([])
    mainForm = MainForm()
    mainForm.show()
    app.exec()
# end main

class MainForm(QWidget):

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

        self.initUi()

        self.myDialog = MyDialog(self)
        # set that something went wrong in the dialog so it should close immediately in the showEvent
        self.myDialog.somethingWentTerriblyWrong = True
    # end function

    def initUi(self):
        # set default form size and location
        self.setGeometry(400, 400, 400, 275)

        # declare a button
        self.btnShowDialog = QPushButton('show dialog')
        self.btnShowDialog.clicked.connect(self.btnShowDialogClicked)

        # increase the font size
        setFontSize(self.btnShowDialog, 16)

        # declare a layout and add the label to the layout
        self.gridLayout = QGridLayout()
        self.gridLayout.addWidget(self.btnShowDialog)

        # add the layout to the form
        self.setLayout(self.gridLayout)
    # end function

    def btnShowDialogClicked(self):
        retVal = self.myDialog.exec()
        print('retVal = ' + str(retVal))
    # end function

# end class

class MyDialog(QDialog):

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

        self.initUi()

        self.somethingWentTerriblyWrong = False
    # end function

    def initUi(self):
        self.setGeometry(250, 250, 250, 175)

        self.lblDialog = QLabel('label on Dialog')

        # center the label and increase the font size
        self.lblDialog.setAlignment(Qt.AlignCenter)
        setFontSize(self.lblDialog, 15)

        self.gridLayout = QGridLayout()
        self.gridLayout.addWidget(self.lblDialog)

        self.setLayout(self.gridLayout)
    # end function

    def showEvent(self, event):
        super(MyDialog, self).showEvent(event)

        # if something went terribly wrong, close this dialog form
        if self.somethingWentTerriblyWrong:
            print('in if self.somethingWentTerriblyWrong:')
            # self.reject()
            self.close()
        # end if

    # end function

# end class

def setFontSize(widget, fontSize):
    font = widget.font()
    font.setPointSize(fontSize)
    widget.setFont(font)
# end function

if __name__ == '__main__':
    main()

MyDialog中,我希望self.reject()或self.close()行能够关闭对话框,但是在Ubuntu 18.04上,至少模式对话框会变暗并挂起:

enter image description here

我确定执行是在if的show事件中的MyDialog语句中得到的,因为终端输出是:

$ python3 test.py 
in if self.somethingWentTerriblyWrong:

我在做什么错?

python pyqt pyqt5
1个回答
0
投票

您正在过早关闭小部件,在showEvent()方法中该小部件可见,但尚未完成设备上的绘画,因此在调用close()方法时,您将停止绘画,并且该绘画未隐藏,因为内部标志未更新,生成undefined behavior

解决方案是在使用close()reject()的瞬间(保留内部标志正确更新的时间)之后的showEvent()之后的瞬间调用QTimer方法(或QMetaObject方法:] >

from PyQt5.QtCore import Qt, QTimer, QMetaObject

# ...


class MyDialog(QDialog):
    # ...
    def showEvent(self, event):
        super(MyDialog, self).showEvent(event)

        # if something went terribly wrong, close this dialog form
        if self.somethingWentTerriblyWrong:
            print("in if self.somethingWentTerriblyWrong:")
            QTimer.singleShot(0, self.close)
            # or
            # - QMetaObject.invokeMethod(self, "close", Qt.QueuedConnection)
            # - QTimer.singleShot(0, self.reject)
            # - QMetaObject.invokeMethod(self, "reject", Qt.QueuedConnection)
    
© www.soinside.com 2019 - 2024. All rights reserved.