Python 如何在showEvent中关闭模式对话框?
我不敢相信我必须问这个问题,但我无法从Python 如何在showEvent中关闭模式对话框?,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,我不敢相信我必须问这个问题,但我无法从showEvent关闭PyQt5模式对话框 下面是一个演示该问题的微型示例程序。此测试程序的预期行为是,由于设置了严重错误的somethingWenterryblyError,因此只要按下btnShowDialog,模态对话框可能会出现一瞬间(如果有那么长的话),然后自动关闭,但从下面的屏幕截图中可以看出,这不会发生 # test.py from PyQt5.QtWidgets import QApplication, QDialog, QWidget,
showEvent
关闭PyQt5模式对话框
下面是一个演示该问题的微型示例程序。此测试程序的预期行为是,由于设置了严重错误的somethingWenterryblyError
,因此只要按下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
语句中,因为终端输出是:
$ python3 test.py
in if self.somethingWentTerriblyWrong:
我做错了什么?您正在过早地关闭小部件,在
showEvent()
方法中,小部件是可见的,但是在调用close()
方法停止绘制时,设备上的绘制尚未完成,并且它没有隐藏,因为内部标志没有更新,生成未定义的行为
解决方案是使用QTimer
或QMetaObject
在showEvent()
之后的一瞬间(保留内部标志正确更新的时间)调用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()