Dialogs are useful GUI components that allow you to communicate with the user (hence the name dialog). They are commonly used for file Open/Save, settings, preferences, or for functions that do not fit into the main UI of the application. They are small modal (or blocking) windows that sit in front of the main application until they are dismissed. Qt actually provides a number of 'special' dialogs for the most common use-cases, allowing you to take advantage of desktop-specific tools for a better user experience.
Standard GUI features — A search dialog
Standard GUI features — A file Open dialog
In Qt dialog boxes are handled by the QDialog
class. To create a new dialog box simply create a new object of QDialog
type (or a subclass), passing in a parent widget, e.g. QMainWindow
as its parent.
Let's create our own QDialog
. The code below creates a window, adds a button to it and connects that button to our
custom method which creates the dialog.
- PyQt5
- PySide2
import sys
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press me for a dialog!")
button.clicked.connect(self.button_clicked)
self.setCentralWidget(button)
def button_clicked(self, s):
print("click", s)
dlg = QDialog(self)
dlg.setWindowTitle("HELLO!")
dlg.exec_()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
import sys
from PySide2.QtWidgets import QApplication, QDialog, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press me for a dialog!")
button.clicked.connect(self.button_clicked)
self.setCentralWidget(button)
def button_clicked(self, s):
print("click", s)
dlg = QDialog(self)
dlg.setWindowTitle("HELLO!")
dlg.exec_()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
In the triggered function (that receives the signal from the button ) we create the dialog instance, passing our QMainWindow
instance as a parent. This will center the QDialog
over the QMainWindow
making it easy to find. If you don't pass the parent, the dialog is usually shown in the middle of the window instead.
Once we have created the dialog, we start it using .exec_()
- just like we did for QApplication
to create the main event loop of our application. That’s not a coincidence: when you exec the QDialog
an entirely new event loop - specific for the dialog - is created.
Remember that there can be only one Qt event loop running at any time! The `QDialog` completely blocks your application execution. Don't start a dialog and expect anything else to happen anywhere else in your application.
We'll cover how you can use multithreading to get you out of this pickle in a later chapter.
*Run it!* The window will display, now click the bug button and a modal window should appear. You can exit by clicking the [x].
Like our very first window, this isn't very interesting. Let's fix that by adding a dialog title and a set of OK and Cancel buttons to allow the user to accept or reject the modal.
To customise the QDialog
we can subclass it — again you can customise the dialog without subclassing, but it's nicer if you do.
- PyQt5
- PySide2
import sys
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QDialogButtonBox,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
)
class CustomDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setWindowTitle("HELLO!")
QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
message = QLabel("Something happened, is that OK?")
self.layout.addWidget(message)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press me for a dialog!")
button.clicked.connect(self.button_clicked)
self.setCentralWidget(button)
def button_clicked(self, s):
print("click", s)
dlg = CustomDialog() # If you pass self, the dialog will be centered over the main window as before.
if dlg.exec_():
print("Success!")
else:
print("Cancel!")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
import sys
from PySide2.QtWidgets import (
QApplication,
QDialog,
QDialogButtonBox,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
)
class CustomDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setWindowTitle("HELLO!")
QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
message = QLabel("Something happened, is that OK?")
self.layout.addWidget(message)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press me for a dialog!")
button.clicked.connect(self.button_clicked)
self.setCentralWidget(button)
def button_clicked(self, s):
print("click", s)
dlg = CustomDialog() # If you pass self, the dialog will be centered over the main window as before.
if dlg.exec_():
print("Success!")
else:
print("Cancel!")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
In the above code, we first create our subclass of QDialog
which we've called CustomDialog
. As for the QMainWindow
we customize it within the __init__
block to ensure that our customizations are created as the object is created. First we set a title for the QDialog
using .setWindowTitle()
, exactly the same as we did for our main window.
The next block of code is concerned with creating and displaying the dialog buttons. This is probably a bit more involved than you were expecting. However, this is due to Qt's flexibility in handling dialog button positioning on different platforms.
You could choose to ignore this and use a standard `QButton` in a layout, but the approach outlined here ensures that your dialog respects the host desktop standards (Ok on left vs. right for example). Breaking these expectations can be incredibly annoying to your users, so I wouldn't recommend it.
The first step in creating a dialog button box is to define the buttons want to show, using namespace attributes from QDialogButtonBox
. Constructing a line of multiple buttons is as simple as OR-ing them together using a pipe (|
). The full list of buttons available is below:
Button types |
---|
QDialogButtonBox.Ok |
QDialogButtonBox.Open |
QDialogButtonBox.Save |
QDialogButtonBox.Cancel |
QDialogButtonBox.Close |
QDialogButtonBox.Discard |
QDialogButtonBox.Apply |
QDialogButtonBox.Reset |
QDialogButtonBox.RestoreDefaults |
QDialogButtonBox.Help |
QDialogButtonBox.SaveAll |
QDialogButtonBox.Yes |
QDialogButtonBox.YesToAll |
QDialogButtonBox.No |
QDialogButtonBox.NoToAll |
QDialogButtonBox.Abort |
QDialogButtonBox.Retry |
QDialogButtonBox.Ignore |
QDialogButtonBox.NoButton |
These should be sufficient to create any dialog box you can think of. For example, to show an OK and a Cancel button we used:
buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
The variable buttons
now contains a bit mask flag representing those two buttons. Next, we must create the QDialogButtonBox
instance to hold the buttons. The flag for the buttons to display is passed in as the first parameter.
To make the buttons have any effect, you must connect the correct QDialogButtonBox
signals to the slots on the dialog. In our case we've connected the .accepted
and .rejected
signals from the QDialogButtonBox
to the handlers for .accept()
and .reject()
on our subclass of QDialog
.
Lastly, to make the QDialogButtonBox
appear in our dialog box we must add it to the dialog layout. So, as for the main window we create a layout, and add our QDialogButtonBox
to it (QDialogButtonBox
is a widget), and then set that layout on our dialog.
*Run it!* Click to launch the dialog and you will see a dialog box with buttons in it.
Congratulations! You've created your first dialog box. Of course, you can continue to add any other content to the dialog box that you like. Simply insert it into the layout as normal.
By [[ topic.created_by.name ]]