I wrote a QMainWindow
, two QDialog
, and one QMessageBox
. The code is as follows:
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())
The process is as follows:
- Start the app, then
MainWindow
shows itself. - Click on the menu item to show
DocumentDialog
. - Click on the button on
DocumentDialog
to showDetailDialog
. - Click on the button on
DetailDialog
to show aQMessageBox
. - Click on the button on
QMessageBox
to close it along withDetailDialog
.
The QMessageBox
is closed, as expected. the weird thing is, DocumentDialog
is over MainWindow
when it shows up. But after QMessageBox
is closed, DocumentDialog
hides behind MainWindow
, why? How not to let DocumentDialog
change it position?
I record a GIF to illustrate the process:
CodePudding user response:
You should set Qt.Popup
Flag for your Dialog :
This makes your Dialog always on top of others.
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())
Result:
Edited:
From Dialog modal
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.
Then as @musicamante said you should change show
to 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()