在 PyQt 中关闭 QMessageBox 后对话框的位置发生了变化
A dialog's position changed after closing a QMessageBox in PyQt
我写了一个QMainWindow
,两个QDialog
,一个QMessageBox
。代码如下:
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QPushButton, QMessageBox, QApplication, QAction, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
action = QAction("Open DocumentDialog", self)
action.triggered.connect(self.show_main_dialog)
menu_bar = self.menuBar()
file = menu_bar.addMenu("File")
file.addAction(action)
self.setWindowTitle("MainWindow")
def show_main_dialog(self):
main_dialog = DocumentDialog(self)
main_dialog.show()
class DocumentDialog(QDialog):
def __init__(self, parent):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open DocumentDetailDialog")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DocumentDialog")
def btn_clicked(self):
detail_dialog = DetailDialog(self)
detail_dialog.show()
class DetailDialog(QDialog):
def __init__(self, parent: QDialog):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open delete message box")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DetailDialog")
def btn_clicked(self):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setText("Are you sure?")
msg_box.setWindowTitle("Delete")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.buttonClicked.connect(self.delete_handler)
msg_box.show()
def delete_handler(self, btn):
self.close()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())
过程如下:
- 启动应用程序,然后
MainWindow
出现。
- 点击菜单项显示
DocumentDialog
。
- 单击
DocumentDialog
上的按钮显示 DetailDialog
。
- 单击
DetailDialog
上的按钮显示 QMessageBox
。
- 单击
QMessageBox
上的按钮将其与 DetailDialog
一起关闭。
QMessageBox
已按预期关闭。奇怪的是,DocumentDialog
出现时 超过 MainWindow
。但是QMessageBox
关闭后,DocumentDialog
躲在后面MainWindow
,为什么?如何不让 DocumentDialog
改变它的位置?
我录制一个GIF来说明这个过程:
您应该为您的对话框设置 Qt.Popup
标志:
这使您的对话框始终位于其他对话框之上。
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QPushButton, QMessageBox, QApplication, QAction, QMainWindow
from PyQt5.QtCore import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
action = QAction("Open DocumentDialog", self)
action.triggered.connect(self.show_main_dialog)
menu_bar = self.menuBar()
file = menu_bar.addMenu("File")
file.addAction(action)
self.setWindowTitle("MainWindow")
def show_main_dialog(self):
main_dialog = DocumentDialog(self)
main_dialog.show()
class DocumentDialog(QDialog):
def __init__(self, parent):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open DocumentDetailDialog")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DocumentDialog")
def btn_clicked(self):
detail_dialog = DetailDialog(self)
detail_dialog.show()
class DetailDialog(QDialog):
def __init__(self, parent: QDialog):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open delete message box")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DetailDialog")
self.setWindowFlags(self.windowFlags() |Qt.Popup)
def btn_clicked(self):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setText("Are you sure?")
msg_box.setWindowTitle("Delete")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.buttonClicked.connect(self.delete_handler)
msg_box.show()
def delete_handler(self, btn):
self.close()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())
结果:
已编辑:
This property holds whether show() should pop up the dialog as modal
or modeless
By default, this property is false and show() pops up the dialog as
modeless. Setting this property to true is equivalent to setting
QWidget::windowModality to Qt::ApplicationModal.
exec() ignores the value of this property and always pops up the
dialog as modal.
然后正如@musicamante 所说,您应该将 show
更改为 exec
:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
action = QAction("Open DocumentDialog", self)
action.triggered.connect(self.show_main_dialog)
menu_bar = self.menuBar()
file = menu_bar.addMenu("File")
file.addAction(action)
self.setWindowTitle("MainWindow")
def show_main_dialog(self):
main_dialog = DocumentDialog(self)
main_dialog.exec()
class DocumentDialog(QDialog):
def __init__(self, parent):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open DocumentDetailDialog")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DocumentDialog")
def btn_clicked(self):
detail_dialog = DetailDialog(self)
detail_dialog.exec()
class DetailDialog(QDialog):
def __init__(self, parent: QDialog):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open delete message box")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DetailDialog")
def btn_clicked(self):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setText("Are you sure?")
msg_box.setWindowTitle("Delete")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.buttonClicked.connect(self.delete_handler)
msg_box.exec()
def delete_handler(self, btn):
self.close()
我写了一个QMainWindow
,两个QDialog
,一个QMessageBox
。代码如下:
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QPushButton, QMessageBox, QApplication, QAction, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
action = QAction("Open DocumentDialog", self)
action.triggered.connect(self.show_main_dialog)
menu_bar = self.menuBar()
file = menu_bar.addMenu("File")
file.addAction(action)
self.setWindowTitle("MainWindow")
def show_main_dialog(self):
main_dialog = DocumentDialog(self)
main_dialog.show()
class DocumentDialog(QDialog):
def __init__(self, parent):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open DocumentDetailDialog")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DocumentDialog")
def btn_clicked(self):
detail_dialog = DetailDialog(self)
detail_dialog.show()
class DetailDialog(QDialog):
def __init__(self, parent: QDialog):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open delete message box")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DetailDialog")
def btn_clicked(self):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setText("Are you sure?")
msg_box.setWindowTitle("Delete")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.buttonClicked.connect(self.delete_handler)
msg_box.show()
def delete_handler(self, btn):
self.close()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())
过程如下:
- 启动应用程序,然后
MainWindow
出现。 - 点击菜单项显示
DocumentDialog
。 - 单击
DocumentDialog
上的按钮显示DetailDialog
。 - 单击
DetailDialog
上的按钮显示QMessageBox
。 - 单击
QMessageBox
上的按钮将其与DetailDialog
一起关闭。
QMessageBox
已按预期关闭。奇怪的是,DocumentDialog
出现时 超过 MainWindow
。但是QMessageBox
关闭后,DocumentDialog
躲在后面MainWindow
,为什么?如何不让 DocumentDialog
改变它的位置?
我录制一个GIF来说明这个过程:
您应该为您的对话框设置 Qt.Popup
标志:
这使您的对话框始终位于其他对话框之上。
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QPushButton, QMessageBox, QApplication, QAction, QMainWindow
from PyQt5.QtCore import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
action = QAction("Open DocumentDialog", self)
action.triggered.connect(self.show_main_dialog)
menu_bar = self.menuBar()
file = menu_bar.addMenu("File")
file.addAction(action)
self.setWindowTitle("MainWindow")
def show_main_dialog(self):
main_dialog = DocumentDialog(self)
main_dialog.show()
class DocumentDialog(QDialog):
def __init__(self, parent):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open DocumentDetailDialog")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DocumentDialog")
def btn_clicked(self):
detail_dialog = DetailDialog(self)
detail_dialog.show()
class DetailDialog(QDialog):
def __init__(self, parent: QDialog):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open delete message box")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DetailDialog")
self.setWindowFlags(self.windowFlags() |Qt.Popup)
def btn_clicked(self):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setText("Are you sure?")
msg_box.setWindowTitle("Delete")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.buttonClicked.connect(self.delete_handler)
msg_box.show()
def delete_handler(self, btn):
self.close()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())
结果:
已编辑:
This property holds whether show() should pop up the dialog as modal or modeless
By default, this property is false and show() pops up the dialog as modeless. Setting this property to true is equivalent to setting QWidget::windowModality to Qt::ApplicationModal.
exec() ignores the value of this property and always pops up the dialog as modal.
然后正如@musicamante 所说,您应该将 show
更改为 exec
:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
action = QAction("Open DocumentDialog", self)
action.triggered.connect(self.show_main_dialog)
menu_bar = self.menuBar()
file = menu_bar.addMenu("File")
file.addAction(action)
self.setWindowTitle("MainWindow")
def show_main_dialog(self):
main_dialog = DocumentDialog(self)
main_dialog.exec()
class DocumentDialog(QDialog):
def __init__(self, parent):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open DocumentDetailDialog")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DocumentDialog")
def btn_clicked(self):
detail_dialog = DetailDialog(self)
detail_dialog.exec()
class DetailDialog(QDialog):
def __init__(self, parent: QDialog):
super().__init__(parent)
vbox = QVBoxLayout()
btn = QPushButton("Open delete message box")
btn.clicked.connect(self.btn_clicked)
vbox.addWidget(btn)
self.setLayout(vbox)
self.setWindowTitle("DetailDialog")
def btn_clicked(self):
msg_box = QMessageBox(self)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setText("Are you sure?")
msg_box.setWindowTitle("Delete")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg_box.buttonClicked.connect(self.delete_handler)
msg_box.exec()
def delete_handler(self, btn):
self.close()