簡體   English   中英

如何在 showEvent 中關閉模式對話框?

[英]how to close a modal dialog in showEvent?

我不敢相信我不得不問這個問題,但我無法從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 上,至少模態對話框會變暗並掛起:

在此處輸入圖像描述

我確定在MyDialog的 show 事件中執行if語句,因為終端 output 是:

$ python3 test.py 
in if self.somethingWentTerriblyWrong:

我究竟做錯了什么?

您過早地關閉了小部件,在showEvent()方法中小部件是可見的,但設備上的繪畫尚未完成,因此在調用close()方法時停止繪畫,並且它沒有隱藏,因為內部標志未更新生成未定義的行為

解決方案是使用QTimerQMetaObjectshowEvent()之后的某個瞬間(留出正確更新內部標志的時間)之后立即調用close()方法(或reject()方法):

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)

根據 eyllanesc 的回答完成工作示例:

# CloseDialogInShowEvent.py

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

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

        self.tmrClose = QTimer(self)
        self.tmrClose.setInterval(200)
        self.tmrClose.timeout.connect(self.tmrCloseTimeout)
    # 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.tmrClose.start()
        # end if
    # end function

    def tmrCloseTimeout(self):
        self.reject()
    # end function

# end class

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

if __name__ == '__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM