我不敢相信我必须问这个问题,但是我无法从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上,至少模式对话框会变暗并挂起:
我确定执行是在if
的show事件中的MyDialog
语句中得到的,因为终端输出是:
$ python3 test.py
in if self.somethingWentTerriblyWrong:
我在做什么错?
您正在过早关闭小部件,在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)