© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
J. M. WillmanBeginning PyQthttps://doi.org/10.1007/978-1-4842-7999-1_8

8. Creating GUIs with Qt Designer

Joshua M Willman1  
(1)
Sunnyvale, CA, USA
 

While building GUIs programmatically gives you more control over the design process, some development tasks may require a quicker approach. Fortunately, Qt provides a great interface for arranging widgets and designing main windows, widgets, or dialogs. The graphical development tool, Qt Designer , is filled with widgets and other tools for building GUIs. With the application’s drag-and-drop interface, you are able to create and customize your own Qt or PyQt applications.

The widgets and other applications you create using Qt Designer can interact with other Qt programs using signals and slots, making it easier to assign behaviors to widgets. This means that more resources can go into coding the functionality and less into layout and design.

In this chapter, you will
  • Install the Qt Designer application

  • Take a look at the different components that comprise the Qt Designer interface

  • Follow along and build an application in Qt Designer, along the way learning how to apply layouts, edit object properties, connect signals and slots, and generate Python code

  • Learn about new PyQt classes such as QFrame class for grouping widgets

Tip

For references or more help beyond the scope of this chapter, check out the Qt Documentation for Qt Designer at https://doc.qt.io/qt-6/qtdesigner-manual.html.

This chapter serves as an introduction to Qt Designer, providing you with the fundamentals you need to get started using the application.

Getting Started with Qt Designer

In this section, we’ll first consider two methods for installing Qt Designer on your computer. After that, we’ll discuss the layout of the Qt Designer GUI.

Installing Qt Designer

As of writing, there are two approaches to installing the latest version of Qt Designer, and they can vary depending upon how much memory you are willing to use.

Your first option is to download the latest version of Qt Creator for Qt 6 from www.qt.io/download. Qt Designer comes bundled with Qt Creator, which is Qt’s official C++ IDE. Be aware that this method works for macOS, Windows, and Linux, but also means that you will be installing the entire Qt Creator IDE as well.

On the Qt downloads web page, you’ll need to locate the option for downloading Qt for open source creators. From there, scroll to the bottom of the page and find the button that says Download the Qt Online Installer. Once the download completes, you’ll need to open up the Qt installer software. You’ll need to create a Qt Account and then follow along with the prompts to install Qt Creator. One thing to note, if you choose to perform a custom installation, you’ll be able to manually select the software you need and save some memory. Once the installation is complete, do a search on your computer to locate Qt Designer.

Another way to install Qt Designer is through PySide6. First, open a shell window and enter the following command to install PySide6:
$ pip3 install PySide6

Use pip instead of pip3 on Windows.

Next, perform a search on your computer for Qt Designer and open the application. After opening Qt Designer, you will see a graphical user interface for creating your own GUIs like the one in Figure 8-1.
Figure 8-1

The Qt Designer interface

Tip

You can change the appearance of the Qt Designer window. In the menu bar, locate the Preferences… menu option, and in the dialog box that appears, look for User Interface Mode. You can select two appearances: Multi Top-Level Windows or Docked Windows. The multilevel layout is great for arranging all of the widgets freely on larger screens.

Before you create your first application, let’s get to know the different menus, tools, and modes that are displayed in the main window in Figure 8-1.

Exploring Qt Designer’s User Interface

When you first open up Qt Designer, you will notice a dialog in the center of the window with the title New Form. This dialog can be seen in Figure 8-2. From here, you can select a template for creating a main window, a widget, or different kinds of dialog boxes. You can also choose what kinds of widgets to add to your project’s layout. Once you have selected a template and the application’s size, an empty window, also known as a form , will appear for you to modify.
Figure 8-2

The New Form dialog box for selecting what type of form to build

At the top of the main window in Figure 8-1, you will notice Qt Designer’s menu bar and toolbar for managing and editing your GUI. On the left side of the main window is the Widget Box dock widget, shown in Figure 8-3, which provides an organized list of layouts and widgets that can be dragged and dropped onto the required locations of your GUI. Other features for tinkering with the form can be accessed by right-clicking and opening up various context menus.
Figure 8-3

The Widget Box dock widget for selecting layouts and widgets

Another very useful dock widget is the Property Editor displayed in Figure 8-4. The properties of windows, widgets, and layouts such as an object’s name, size constraints, status tips, and more can all be altered using the Property Editor. Each widget you add to a form will have its own set of properties as well as ones that the widget inherits from other classes. To select a specific widget, you can either click on the object in the form or on the widget’s name in the Object Inspector dock widget.
Figure 8-4

The Property Editor dock widget for setting the attributes of widgets

The Object Inspector in Figure 8-5 allows you to view all of the objects that are currently being used as well as their hierarchical layout. You can see how the MainWindow is listed first, followed by the centralwidget, and all of its widgets. If your form also has a menu or toolbar, then they will also be listed in the Object Inspector along with their corresponding actions.
Figure 8-5

The Object Inspector displays the widget, layout, and menu objects

Note

The main layout for your GUI is not displayed in the Object Inspector. A broken layout icon (a red circle with a slash) is displayed on the central widget or on containers if no layout has been assigned to them.

In Qt Designer, it is also possible to create, edit, and delete signals and slots between objects using the Signal/Slot Editor. You should be aware that although you can connect signals and slots, you will not always be able to completely configure your widgets and will sometimes need to complete that yourself in code. The Signal/Slot Editor can be seen in Figure 8-6. Qt Designer also provides an editing mode for connecting widgets.
Figure 8-6

The Signal/Slot Editor for connecting the signals and slots of objects

Items in a menu, a submenu, or a toolbar are assigned commands by using actions. These actions can then be given a shortcut key, made checkable, and more. The Action Editor seen in Figure 8-7 gives you access to working with actions. For more information about assigning actions, refer to Chapter 5.
Figure 8-7

The Action Editor is used to manage the actions of menu items

Finally, there is the Resource Browser that allows you to specify and manage resources you need to use in your application. These resources can include images and icons. The Resource Browser dock widget can be seen in Figure 8-8.
Figure 8-8

The Resource Browser for working with resources such as images and icons

If you need to add resources, you first need to create a new resource file. To do so, click the pencil in the top-left corner of the Resource Browser dock widget. This will open an Edit Resources dialog similar to the one in Figure 8-9.
Figure 8-9

The Edit Resources dialog

Next, click on the Create New Resource button, navigate to the correct directory, and enter a name for the resource file. The file will be saved with a .qrc file extension, which stands for Qt Resource Collection and contains a list of all the resources used in your program. From here, create a prefix for managing the types of resources and begin adding files such as images and icons. When you are finished, click the OK button, and the files will be added to the Resource Browser.

Note

Support for resources and .qrc files in PyQt6 is different than in PyQt5. To access the resources, you may have to consider using other PyQt classes, such as QFile or QDir, or use the file path to the resource.

Qt Designer’s Editing Modes

In Qt Designer, there are four different editing modes that can be accessed either in the Edit menu or from Qt Designer’s toolbar. Take a look at Figure 8-10 to help you locate the widgets in the toolbar.
  1. 1.

    Edit Widgets – Widgets can be dragged and dropped to a form, layouts can be applied, and objects can be edited both on the form and in the Property Editor. This is the default mode.

     
  2. 2.

    Edit Signals/Slots – Connect signals and slots for widgets and layouts. To create connections, click on an object and drag the cursor toward an object that will receive the signal. Items that can be connected will be highlighted as the mouse cursor moves over them. To create the connection, release the mouse button once a line with an arrow connects the two objects. Then configure the signals and slots. Use in conjunction with the Signal/Slot Editor dock widget to edit connections.

     
  3. 3.

    Edit Buddies – Connect QLabel widgets with shortcuts to input widgets such as QLineEdit or QTextEdit. The input widget becomes the QLabel object’s “buddy.” When the user enters the label’s shortcut key, the focus moves to the input widget.

     
  4. 4.

    Edit Tab Order – Set the order in which widgets receive focus when the tab key is pressed. This allows the user to navigate through the different widgets, improving your application’s usability.

     
Figure 8-10

Qt Designer’s Editing Modes (outlined in red). (From left to right) Edit Widgets, Edit Signals/Slots, Edit Buddies, Edit Tab Order

Creating an Application in Qt Designer

When you are creating your GUI’s windows and widgets, you will probably continue to make slight adjustments to your application before it is finished. Fortunately, there are a few steps you can follow to simplify the building process.
  1. 1.

    Select a form – In the New Form dialog (shown in Figure 8-2), choose from one of the available templates, Main Window, Widget, or a type of Dialog. You can also add and preview widgets to include in your GUI.

     
  2. 2.

    Arrange objects on the form – Use Qt Designer’s drag-and-drop mechanics to place widgets on the form. Then assign layouts to containers and the main window.

     
  3. 3.

    Edit the properties of objects – Click on the objects in the form and edit their features in the Property Editor dock widget.

     
  4. 4.

    Connect signals and slots – Use the Signals/Slots Editing mode to link signals to slots.

     
  5. 5.

    Preview your GUI – Examine the form before saving it as a UI file with the .ui extension.

     
  6. 6.

    Create and edit Python code – Utilize the pyuic compiler to convert the UI file to readable and editable Python code.

     

The following project will cover these steps in addition to many of the basic concepts for creating GUIs using Qt Designer.

Project 8.1 – Keypad GUI

The GUI in Figure 8-11 should be a familiar one – a keypad.
Figure 8-11

Keypad GUI

Keypads are relatively simple interfaces, with sets of buttons for digits, symbols, or letters used as input devices for passcodes or telephone numbers. They can be found on a number of devices such as calculators, cell phones, and locks.

Explanation for the Keypad GUI

The keypad application is composed of two Python files: keypad_gui.py and keypad_main.py. The keypad_gui.py contains the Python class generated from the UI file built from Qt Designer. In order to use that code, we need to create a customized class in a separate file, keypad_main.py, to import and set up the GUI.

The keypad GUI consists of four QLineEdit widgets to input only numeric values, 12 QPushButton widgets, and a single QLabel to display information about how to use the interface. The asterisk button allows users to clear their current input, and the hash button is for confirming the user’s four-digit input.

We’ll begin by creating the window in Qt Designer before discussing the code.

Selecting a Form

Begin by opening up Qt Designer. Choose the Widget template from the New Form dialog box. We will use the Default screen size. Select Create. This opens up a blank QWidget form with a grid of dots inside of the Qt Designer interface similar to Figure 8-1 (although that screenshot displays a QMainWindow form).

Arranging Objects on the Form

You could begin by adjusting certain features of the form such as the window size or the background color. Instead, let’s first add whatever widgets we need for the project by dragging and dropping them into the main window from the Widget Box dialog on the left of the window.

Locate the QLabel widget (called Label in the dialog) and drag one onto the form. Then drag two QFrame containers (called Frame) onto the form like in Figure 8-12. You can resize the frames by clicking on them and moving the edges of the frame. Then drag four QLineEdit input widgets (called Line Edit) and arrange them in the top QFrame container. They will overlap, but that will be fixed when you apply layouts to the frames and the main window. When an object is dragged on top of a container where it can be placed, the container will be highlighted to indicate that you can drop the widget inside. In addition, place 12 QPushButton widgets (called Push Button) in the bottom frame.
Figure 8-12

The form with a label and two frames (left) and with the line edit widgets and push buttons added (right)

Before moving on, let’s take a moment to learn more about the QFrame container as it is a very useful element in GUI development.

The QFrame Class
The QFrame class is used as a container to group and surround widgets, or to act as a placeholder in GUI applications. You can also apply a frame style to a QFrame instance to visually separate it from nearby widgets. The following bit of code shows an example of how to create a frame object in a main window, modify its properties, and add a widget.
        # Create a widget to place in the frame
        button = QPushButton("Enter")
        grid = QGridLayout()
        grid.addWidget(button, 0, 0)
        # Create the frame and set its parameters
        frame = QFrame() # Create a QFrame object
        size_policy = QSizePolicy(
            QSizePolicy.Policy.Expanding,
            QSizePolicy.Policy.Preferred)
        frame.setSizePolicy(size_policy)
        frame.setFrameShape(QFrame.Shape.Box)
        frame.setFrameShadow(QFrame.Shadow.Raised)
        frame.setLineWidth(3)
        frame.setMidLineWidth(5)
        # Set the layout for the QFrame object
        frame.setLayout(grid)
        self.setCentralWidget(frame)

Using the method setSizePolicy(), we can define how a frame should resize. A frame object can have a number of different styles of frames, including Box, Panel, StyledPanel, or NoFrame. The style of the frame can be adjusted using the setFrameShadow(), setLineWidth(), and setMidLineWidth() methods. Different types of shadow include Plain, Raised, and Sunken.

For practice, try creating a simple window from the previous code.

Applying Layouts in Qt Designer

The next step is to add layouts to all of the containers and to the main window. This is an important step that ensures items are placed and resized correctly. Layouts can be added either from the toolbar or from context menus. It is possible to add more widgets to existing layouts once they have been set.

Since Qt Designer uses a drag-and-drop interface, you only need to place the objects on the form close to where you want them to be and then select one of the four layouts – QGridLayout, QHBoxLayout, QVBoxLayout, or QFormLayout – from the Widget Box dialog, and Qt Designer will take care of arranging them. For more information about the types of layouts in PyQt, refer to Chapter 4.

Right-click on the top-most frame to open a context menu (demonstrated in Figure 8-13). Scroll down to the last option, Lay out, and select Lay Out Horizontally. Do the same thing for the bottom frame, but this time select Lay Out in a Grid.
Figure 8-13

Open a context menu to select layouts for containers and windows

The top-level layout of a form can be set by right-clicking on the form itself in the main window and locating the layout you want to use. For the keypad GUI, right-click and select Lay Out Vertically. Your GUI should look like Figure 8-14. If the widgets are not aligned properly, you can also open the context menu, select Break Layout, and rearrange the widgets. The option Simplify Grid Layout may also help you arrange items in the grid layout.
Figure 8-14

The keypad GUI with layouts

Editing the Properties of Objects

Once you have the layouts prepared, you should begin editing the features of the objects. This step could also be accomplished earlier when you place objects on the form.

The Property Editor is shown in Figure 8-4. It is organized into two columns: Property and Value. The properties are organized by Qt Classes.

To access and make changes to specific containers, widgets, layouts, or even the main window, you can click on them in the form or in the Object Inspector. If a property is edited in the Property Editor, you can locate it with the following pattern:

Qt Class (Property column) ➤ Property name ➤ (submenu, if any) ➤ Value column ➤ parameter

The following are the steps that you can follow along with to create the keypad GUI in Qt Designer:
  1. 1.

    Change window title: QWidgetwindowTitle8.1 – Keypad GUI

     
  2. 2.

    Double-click on the QLabel. Change text to enter a passcode.

     
  3. 3.
    Change QLabel properties:
    1. a.

      QWidgetfontPoint Size20

       
    2. b.

      To edit palette colors, you will need to locate the palette property that opens a dialog box. Here, you can change the colors for different parts of an object. To change the color of the text in the label object: QWidgetpaletteChange PaletteWindow Textwhite

       
    3. c.

      QLabelalignmentHorizontalAlignHCenter

       
     
  4. 4.
    Change top frame properties:
    1. a.

      QWidgetsizePolicyVertical Stretch1

       
    2. b.

      QFrameframeShapeNoFrame

       
    3. c.

      QFrameframeShadowPlain

       
     
  5. 5.
    For each of the four QLineEdit widgets, modify their properties:
    1. a.

      QWidgetsizePolicyVertical PolicyExpanding

       
    2. b.

      QWidgetfontPoint Size30

       
    3. c.

      QLineEditalignmentHorizontalAlignHCenter

       
     
  6. 6.
    Change bottom frame properties:
    1. a.

      QWidgetsizePolicyVertical Stretch2

       
    2. b.

      QFrameframeShapeBox

       
    3. c.

      QFrameframeShadowSunken

       
    4. d.

      QFramelineWidth2

       
     
  7. 7.

    Double-click on each of the buttons and change their text to 0–9, *, and #. (Refer to Figure 8-11.)

     
  8. 8.
    Edit each of the button’s properties:
    1. a.

      QWidgetsizePolicyVertical PolicyExpanding

       
    2. b.

      QWidgetfontPoint Size36

       
     
  9. 9.
    Resize the main window:
    1. a.

      QWidgetgeometryWidth302

       
    2. b.

      QWidgetgeometryHeight406

       
     
  10. 10.

    Click on the form and change its background color: QWidgetpaletteChange PaletteWindowdark gray

     
  11. 11.

    In the Object Inspector, double-click on each of the default object names for the frames, line edits, and buttons, and edit them. Doing this will be helpful later on so that we can distinguish the buttons when looking at the code. The object name is used to reference the objects.

     

After you have followed along with each of the steps, the form should look similar to Figure 8-11.

Previewing Your GUI

It is often useful to view and interact with the form before exporting it to code. Not only can this be useful for checking the visual appearance of your GUI, but previewing also helps to make sure the signals and slots, resizing the window, and other functions are working properly.

To preview a form, open the Form menu and select Preview or use the hotkeys Ctrl+R for Windows or Command+R for macOS. If you are satisfied with your form, save it as a UI file with the .ui extension. Qt Designer UI files are written in XML format and contain the widget tree representation for creating a GUI.

Connecting Signals and Slots in Qt Designer

Switch to the Edit Signals/Slots mode by selecting it from the toolbar. Qt Designer has a simple interface for connecting signals and slots. Click on the object that will emit a signal and drag it to the object that will receive the signal. For the keypad GUI, we are only making one set of connections. The remaining signals and slots will be handled by manually coding them.

When the “*” button is clicked, we want to clear all four line edit widgets. Click on the button and drag the red arrow to the first line edit object. A dialog box will appear (displayed in Figure 8-15) that allows you to select the methods for both the signal and the slot.
Figure 8-15

The dialog box for connecting signals and slots

Tip

When connecting signals and slots, make sure to check the “Show signals and slots inherited from QWidget” checkbox to access more methods.

Select clicked() for the button and clear() for the line edit. Finish connecting the other three line edit widgets. Refer to Figure 8-16 as a guide for connecting the widgets. Make sure to save your work before moving on. For this example, the file is saved as keypad.ui.
Figure 8-16

The keypad GUI with signal and slot connections

Creating Python Code from Qt Designer

Qt Designer uses the Qt utility User Interface Compiler (uic) to generate code and create the user interface. However, since you are using PyQt6, you must use the uic module, pyuic6, to load .ui files and convert the XML code to Python code. The pyuic6 utility is a command line interface for interacting with uic.

Open up your system’s shell and navigate to the directory that contains the UI file. The following line shows the format for XML to Python:
$ pyuic6 filename.ui -o filename.py

To output a Python file, you need to include the -o flag and the Python file to be written to, filename.py. This command will generate a single Python class.

With your new file created, the best practice is to create a separate script to inherit from your newly created user interface class. Another option is to create an executable file that can display the GUI. This can be done by including the -x flag for execute, demonstrated for you in the following code:
pyuic6 -x filename.ui -o filename.py
Note

If you make changes to the GUI in Qt Designer after creating the Python script, you will need to call pyuic6 again to update the application.

One final note about running the pyuic6 command. If you find that pyuic6 is not found, you can try using the following format:
$ python3 -m PyQt6.uic.pyuic filename.ui -o filename.py

Change python3 to python on Windows.

Generating Code Using pyuic6
To generate the keypad_gui.py file, navigate to where you saved keypad.ui and run the following line:
$ python3 -m PyQt6.uic.pyuic keypad.ui -o keypad_gui.py
The following Python code in Listings 8-1 to 8-10 is produced from running the pyuic6 command. It has not been altered so that we can look over what pyuic6 produces. Do note that even if you followed along with the tutorial to make the keypad GUI, your code may not look exactly the same.
# keypad_gui.py
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Keypad(object):
    def setupUi(self, Keypad):
        Keypad.setObjectName("Keypad")
        Keypad.resize(302, 406)
Listing 8-1

Python class created from keypad.ui

PyQt6 modules are first imported. The Ui_Keypad class inherits object, denoting that this class is the root for all other classes.

From there, the member function setupUi() of the class Ui_Keypad is used to build a widget tree on the Keypad widget. A widget tree is used to represent the organization of widgets in a UI. So the setupUi() method is passed a widget that will display the interface (typically QWidget, QDialog, or QMainWindow) and compose the UI based upon the widgets and connections we used to create it along with the parameters it inherits.

Every widget in Qt has a palette that contains information about how they will be drawn in the window. The QPalette class contains the color groups for each widget during one of three possible states – Active, Inactive, or Disabled.

Since we altered the palette’s background color for the main window to dark gray, those changes will appear in Listing 8-2.
# keypad_gui.py
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Active,
            QtGui.QPalette.ColorRole.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(52, 48, 47))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Active,
            QtGui.QPalette.ColorRole.Window, brush)
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Inactive,
            QtGui.QPalette.ColorRole.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(52, 48, 47))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Inactive,
            QtGui.QPalette.ColorRole.Window, brush)
        brush = QtGui.QBrush(QtGui.QColor(52, 48, 47))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Disabled,
            QtGui.QPalette.ColorRole.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(52, 48, 47))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Disabled,
            QtGui.QPalette.ColorRole.Window, brush)
        Keypad.setPalette(palette)
Listing 8-2

Setting up the palette for the keypad GUI

You can see that even though we only changed the palette color, that change is handled for all three states automatically. The QBrush class is used to apply the colors and patterns to widgets. The setPalette() method applies palette to the Keypad class.

The vertical layout for the Keypad class is instantiated in Listing 8-3.
# keypad_gui.py
        self.verticalLayout = QtWidgets.QVBoxLayout(Keypad)
        self.verticalLayout.setObjectName(“verticalLayout”)
Listing 8-3

Creating the main window’s layout manager

The changes made to the QLabel object are reflected in Listing 8-4. These include modifying the label’s palette settings so that the color of the font is white and adding the label to verticalLayout.
# keypad_gui.py
        self.label = QtWidgets.QLabel(Keypad)
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Active,
            QtGui.QPalette.ColorRole.WindowText, brush)
        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Inactive,
            QtGui.QPalette.ColorRole.WindowText, brush)
        brush = QtGui.QBrush(QtGui.QColor(127, 127, 127))
        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
        palette.setBrush(QtGui.QPalette.ColorGroup.Disabled,
            QtGui.QPalette.ColorRole.WindowText, brush)
        self.label.setPalette(palette)
        font = QtGui.QFont()
        font.setPointSize(20)
        self.label.setFont(font)
        self.label.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignCenter)
        self.label.setObjectName("label")
        self.verticalLayout.addWidget(self.label)
Listing 8-4

Creating the header label

The changes to label instance’s font and alignment are also reflected in the code.

The first QFrame container, frame, in Listing 8-5 holds four QLineEdit instances and uses a QHBoxLayout to arrange the widgets.
# keypad_gui.py
        self.frame = QtWidgets.QFrame(Keypad)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Preferred,
            QtWidgets.QSizePolicy.Policy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(
            self.frame.sizePolicy().hasHeightForWidth())
        self.frame.setSizePolicy(sizePolicy)
        self.frame.setFrameShape(
            QtWidgets.QFrame.Shape.NoFrame)
        self.frame.setFrameShadow(
            QtWidgets.QFrame.Shadow.Plain)
        self.frame.setLineWidth(0)
        self.frame.setObjectName("frame")
        self.horizontalLayout = QtWidgets.QHBoxLayout(
            self.frame)
        self.horizontalLayout.setObjectName(
            "horizontalLayout")
Listing 8-5

Creating the frame for the QLineEdit widgets in the keypad GUI

The adjustments to frame can be seen in the previous code. The vertical stretch is changed to 1, the frame shape is set to NoFrame, and the shadow is set to Plain. The line edits that frame contains are constructed in Listing 8-6.
# keypad_gui.py
        self.line_edit1 = QtWidgets.QLineEdit(self.frame)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Expanding,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.line_edit1.sizePolicy().hasHeightForWidth())
        self.line_edit1.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(30)
        self.line_edit1.setFont(font)
        self.line_edit1.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignCenter)
        self.line_edit1.setObjectName("line_edit1")
        self.horizontalLayout.addWidget(self.line_edit1)
        self.line_edit2 = QtWidgets.QLineEdit(self.frame)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Expanding,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.line_edit2.sizePolicy().hasHeightForWidth())
        self.line_edit2.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(30)
        self.line_edit2.setFont(font)
        self.line_edit2.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignCenter)
        self.line_edit2.setObjectName("line_edit2")
        self.horizontalLayout.addWidget(self.line_edit2)
        self.line_edit3 = QtWidgets.QLineEdit(self.frame)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Expanding,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.line_edit3.sizePolicy().hasHeightForWidth())
        self.line_edit3.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(30)
        self.line_edit3.setFont(font)
        self.line_edit3.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignCenter)
        self.line_edit3.setObjectName("line_edit3")
        self.horizontalLayout.addWidget(self.line_edit3)
        self.line_edit4 = QtWidgets.QLineEdit(self.frame)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Expanding,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.line_edit4.sizePolicy().hasHeightForWidth())
        self.line_edit4.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(30)
        self.line_edit4.setFont(font)
        self.line_edit4.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignCenter)
        self.line_edit4.setObjectName("line_edit4")
        self.horizontalLayout.addWidget(self.line_edit4)
        self.verticalLayout.addWidget(self.frame)
Listing 8-6

Code for the QLineEdit widgets in the keypad GUI

There is a lot of repetition in this large block of code. That is because the four line edits all have the same changes made. By looking at one instance, you can understand the other three.

Each of the four line edit widgets has size policies that allow them to stretch if the window resizes in both the vertical and horizontal directions by using QSizePolicy.Policy.Expanding. Changes made to the font size and the alignment also show up. The QLineEdit widgets are then arranged in the horizontalLayout of the frame container. The frame object is finally added to the verticalLayout of the main window.

The bottom frame container is instantiated in Listing 8-7, and its size policy and style attributes are set.
# keypad_gui.py
        self.frame_2 = QtWidgets.QFrame(Keypad)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Preferred,
            QtWidgets.QSizePolicy.Policy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(2)
        sizePolicy.setHeightForWidth(
            self.frame_2.sizePolicy().hasHeightForWidth())
        self.frame_2.setSizePolicy(sizePolicy)
        self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.Box)
        self.frame_2.setFrameShadow(
            QtWidgets.QFrame.Shadow.Sunken)
        self.frame_2.setLineWidth(2)
        self.frame_2.setObjectName("frame_2")
        self.gridLayout = QtWidgets.QGridLayout(self.frame_2)
        self.gridLayout.setObjectName("gridLayout")
Listing 8-7

Creating the frame for the QPushButton widgets in the keypad GUI

The bottom frame is guaranteed to take up more vertical space since its vertical stretch factor is set to 2. The frame has a Box shape, Sunken shadow, and lineWidth of 2. The layout inside frame_2 holds the 12 buttons and uses a grid layout.

The names of the buttons and the line edit widgets reflect the changes we made in Qt Designer. This makes it easier in the Python script to distinguish the widgets in the keypad interface. Let’s take a look at the code for the 12 QPushButton widgets in Listing 8-8.
# keypad_gui.py
        self.button_7 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_7.sizePolicy().hasHeightForWidth())
        self.button_7.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_7.setFont(font)
        self.button_7.setObjectName("button_7")
        self.gridLayout.addWidget(self.button_7, 0, 0, 1, 1)
        self.button_8 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_8.sizePolicy().hasHeightForWidth())
        self.button_8.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_8.setFont(font)
        self.button_8.setObjectName("button_8")
        self.gridLayout.addWidget(self.button_8, 0, 1, 1, 1)
        self.button_9 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_9.sizePolicy().hasHeightForWidth())
        self.button_9.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_9.setFont(font)
        self.button_9.setObjectName("button_9")
        self.gridLayout.addWidget(self.button_9, 0, 2, 1, 1)
        self.button_4 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_4.sizePolicy().hasHeightForWidth())
        self.button_4.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_4.setFont(font)
        self.button_4.setObjectName("button_4")
        self.gridLayout.addWidget(self.button_4, 1, 0, 1, 1)
        self.button_5 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_5.sizePolicy().hasHeightForWidth())
        self.button_5.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_5.setFont(font)
        self.button_5.setObjectName("button_5")
        self.gridLayout.addWidget(self.button_5, 1, 1, 1, 1)
        self.button_6 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_6.sizePolicy().hasHeightForWidth())
        self.button_6.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_6.setFont(font)
        self.button_6.setObjectName("button_6")
        self.gridLayout.addWidget(self.button_6, 1, 2, 1, 1)
        self.button_3 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_3.sizePolicy().hasHeightForWidth())
        self.button_3.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_3.setFont(font)
        self.button_3.setObjectName("button_3")
        self.gridLayout.addWidget(self.button_3, 2, 0, 1, 1)
        self.button_2 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_2.sizePolicy().hasHeightForWidth())
        self.button_2.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_2.setFont(font)
        self.button_2.setObjectName("button_2")
        self.gridLayout.addWidget(self.button_2, 2, 1, 1, 1)
        self.button_1 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_1.sizePolicy().hasHeightForWidth())
        self.button_1.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_1.setFont(font)
        self.button_1.setObjectName("button_1")
        self.gridLayout.addWidget(self.button_1, 2, 2, 1, 1)
        self.button_star = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_star.sizePolicy().hasHeightForWidth())
        self.button_star.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_star.setFont(font)
        self.button_star.setObjectName("button_star")
        self.gridLayout.addWidget(
            self.button_star, 3, 0, 1, 1)
        self.button_0 = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_0.sizePolicy().hasHeightForWidth())
        self.button_0.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_0.setFont(font)
        self.button_0.setObjectName("button_0")
        self.gridLayout.addWidget(self.button_0, 3, 1, 1, 1)
        self.button_hash = QtWidgets.QPushButton(self.frame_2)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Policy.Minimum,
            QtWidgets.QSizePolicy.Policy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.button_hash.sizePolicy().hasHeightForWidth())
        self.button_hash.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(36)
        self.button_hash.setFont(font)
        self.button_hash.setObjectName("button_hash")
        self.gridLayout.addWidget(
            self.button_hash, 3, 2, 1, 1)
        self.verticalLayout.addWidget(self.frame_2)
Listing 8-8

Creating the QPushButton widgets that are arranged in the bottom frame

The 12 QPushButton widgets are created. The buttons are able to expand vertically using the Expanding flag, and their font size is set to 36. Every button is then added to the grid layout of frame_2, which is then added to the vertical layout of the main window.

Listing 8-9 connects the signals for the button_star instance to the line edit widgets, clearing the text whenever the button is pressed. This allows the user a way to delete their input and try again.
# keypad_gui.py
        self.retranslateUi(Keypad)
        self.button_star.clicked.connect(
            self.line_edit1.clear)
        self.button_star.clicked.connect(
            self.line_edit2.clear)
        self.button_star.clicked.connect(
            self.line_edit3.clear)
        self.button_star.clicked.connect(
            self.line_edit4.clear)
        QtCore.QMetaObject.connectSlotsByName(Keypad)
Listing 8-9

Connecting the signals and slots for the keypad GUI

The retranslateUi() method in Listing 8-10 handles how to display text in the GUI in the case that a different language is used.
# keypad_gui.py
    def retranslateUi(self, Keypad):
        _translate = QtCore.QCoreApplication.translate
        Keypad.setWindowTitle(
            _translate("Keypad", "8.1 - Keypad GUI"))
        self.label.setText(
            _translate("Keypad", "Enter a passcode"))
        self.button_7.setText(_translate("Keypad", "7"))
        self.button_8.setText(_translate("Keypad", "8"))
        self.button_9.setText(_translate("Keypad", "9"))
        self.button_4.setText(_translate("Keypad", "4"))
        self.button_5.setText(_translate("Keypad", "5"))
        self.button_6.setText(_translate("Keypad", "6"))
        self.button_3.setText(_translate("Keypad", "3"))
        self.button_2.setText(_translate("Keypad", "2"))
        self.button_1.setText(_translate("Keypad", "1"))
        self.button_star.setText(_translate("Keypad", "*"))
        self.button_0.setText(_translate("Keypad", "0"))
        self.button_hash.setText(_translate("Keypad", "#"))
Listing 8-10

Code for the retranslateUi() method

QCoreApplication.translate returns the translated text of the second argument passed to the method.

Creating a New Script to Build a GUI

The following section creates the class that inherits Ui_Keypad and sets up the GUI application. In order to utilize the Ui_Keypad class that was created using Qt Designer, we’ll create a new Python file, keypad_main.py. The KeypadGUI class created in keypad_main.py will inherit from the Ui_Keypad class.

We begin by importing the modules needed for this project in Listing 8-11, including the Ui_Keypad class and a new PyQt class, QIntValidator. PyQt provides a few classes that can be used to verify the types of input text. QIntValidator will be used to check if the values input into the QLineEdit widgets are integers.
# keypad_main.py
# Import necessary modules
import sys
from PyQt6.QtWidgets import (QApplication, QWidget,
    QMessageBox)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QIntValidator
from keypad_gui import Ui_Keypad
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.ui = Ui_Keypad()
        self.ui.setupUi(self)
        self.initializeUI()
        self.show()
if __name__ == "__main__":
    app = QApplication(sys.argv)
    Keypad = MainWindow()
    sys.exit(app.exec())
Listing 8-11

Setting up the main window for the keypad GUI

The MainWindow class is created using a single inheritance approach where it inherits its properties from a single parent class, QWidget. The user interface is set up in the __init__() method in the following lines:
        self.ui = Ui_Keypad()
        self.ui.setupUi(self)
In the initializeUI() method in Listing 8-12, local modifications are made to the QLineEdit widgets. Here, the line edit widget’s focus policy is set to NoFocus so that users can only enter input in the correct order, from left to right.
# keypad_main.py
    def initializeUI(self):
        """Set up the application's GUI."""
        # Update other line_edit features
        # Set the max number of characters allowed
        self.ui.line_edit1.setMaxLength(1)
        # User can only enter ints from 0-9
        self.ui.line_edit1.setValidator(QIntValidator(0, 9))
        # Widget does not accept focus
        self.ui.line_edit1.setFocusPolicy(
            Qt.FocusPolicy.NoFocus)
        self.ui.line_edit2.setMaxLength(1)
        self.ui.line_edit2.setValidator(QIntValidator(0, 9))
        self.ui.line_edit2.setFocusPolicy(
            Qt.FocusPolicy.NoFocus)
        self.ui.line_edit3.setMaxLength(1)
        self.ui.line_edit3.setValidator(QIntValidator(0, 9))
        self.ui.line_edit3.setFocusPolicy(
            Qt.FocusPolicy.NoFocus)
        self.ui.line_edit4.setMaxLength(1)
        self.ui.line_edit4.setValidator(QIntValidator(0, 9))
        self.ui.line_edit4.setFocusPolicy(
            Qt.FocusPolicy.NoFocus)
Listing 8-12

Code for the initializeUI() method in the keypad GUI

Then we connect the signals and slots for the button widgets in Listing 8-13. When each button is clicked, it sends a signal that is connected to the numberClicked() slot. Rather than creating a separate method for each button, the lambda function is used to reuse a method for signals. lambda calls the numberClicked() function and passes it a new parameter every time, in this case, the specific text from each button.
# keypad_main.py
        # 4-digit passcode
        self.passcode = 8618
        # Add signal/slot connections for buttons
        self.ui.button_0.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_0.text()))
        self.ui.button_1.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_1.text()))
        self.ui.button_2.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_2.text()))
        self.ui.button_3.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_3.text()))
        self.ui.button_4.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_4.text()))
        self.ui.button_5.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_5.text()))
        self.ui.button_6.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_6.text()))
        self.ui.button_7.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_7.text()))
        self.ui.button_8.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_8.text()))
        self.ui.button_9.clicked.connect(
            lambda: self.numberClicked(
                self.ui.button_9.text()))
        self.ui.button_hash.clicked.connect(
            self.checkPasscode)
Listing 8-13

Setting up the signals for the push buttons in the keypad GUI

When a user clicks on a button, that button’s number needs to appear in the correct line edit widget from left to right. A widget receives focus if its text() value is empty. This is handled in the numberClicked() slot in Listing 8-14.
# keypad_main.py
    def numberClicked(self, text_value):
        """When a button with a digit is pressed, check if
        the text for QLineEdit widgets are empty. If empty,
        set the focus to the correct widget and enter text
        value."""
        if self.ui.line_edit1.text() == "":
            self.ui.line_edit1.setFocus()
            self.ui.line_edit1.setText(text_value)
            self.ui.line_edit1.repaint()
        elif (self.ui.line_edit1.text() != "") and
            (self.ui.line_edit2.text() == ""):
            self.ui.line_edit2.setFocus()
            self.ui.line_edit2.setText(text_value)
            self.ui.line_edit2.repaint()
        elif (self.ui.line_edit1.text() != "") and
            (self.ui.line_edit2.text() != "") and
            (self.ui.line_edit3.text() == ""):
            self.ui.line_edit3.setFocus()
            self.ui.line_edit3.setText(text_value)
            self.ui.line_edit3.repaint()
        elif (self.ui.line_edit1.text() != "") and
            (self.ui.line_edit2.text() != "") and
            (self.ui.line_edit3.text() != "") and
            (self.ui.line_edit4.text() == ""):
            self.ui.line_edit4.setFocus()
            self.ui.line_edit4.setText(text_value)
            self.ui.line_edit4.repaint()
Listing 8-14

Creating the numberClicked() slot

The repaint() method is used to ensure that text is updated in the QLineEdit widgets.

Finally, if the user presses the # button, the slot checkPasscode() in Listing 8-15 checks if the user entered a passcode that matches passcode. If the input does not match, the line edit widgets are reset. This project could be designed so that the password is read from a file or from a database.
# keypad_main.py
    def checkPasscode(self):
        """Concatenate the text values from the 4 QLineEdit
        widgets, and check to see if the passcode entered by
        user matches existing passcode."""
        entered_passcode = self.ui.line_edit1.text() +
            self.ui.line_edit2.text() +
            self.ui.line_edit3.text() +
            self.ui.line_edit4.text()
        if len(entered_passcode) == 4 and
            int(entered_passcode) == self.passcode:
            QMessageBox.information(
                self, "Valid Passcode!", "Valid Passcode!",
                QMessageBox.StandardButton.Ok)
            self.close()
        else:
            QMessageBox.warning(
                self, "Error Message", "Invalid Passcode.",
                QMessageBox.StandardButton.Close)
            self.ui.line_edit1.clear()
            self.ui.line_edit2.clear()
            self.ui.line_edit3.clear()
            self.ui.line_edit4.clear()
            self.ui.line_edit1.setFocus()
Listing 8-15

Creating the checkPasscode() slot

A QMessageBox appears to inform the user about the outcome of their password. When you run this script, your GUI should look similar to Figure 8-11.

We have only covered some of the features of Qt Designer while building the keypad GUI. In the following section, we’ll look at a few other important topics.

Extra Tips for Using Qt Designer

The following section briefly covers three additional topics:
  1. 1.

    Creating GUIs with menus

     
  2. 2.

    Displaying images in Qt Designer

     
  3. 3.

    Using style sheets

     

Setting Up Main Windows and Menus

Open Qt Designer and select the Main Window template from the Form Menu in Figure 8-2. This creates a main window with a menu bar and status bar by default. You can see a main window form displayed in Figure 8-1.

Adding Menus and Submenus in Qt Designer

Adding menus in Qt Designer is simple. Double-click on the Type Here placeholder text in the menu bar and enter the title of the menu. This process is shown in Figure 8-17. If you want to create a shortcut, you can also add the ampersand, &, to the beginning of the menu’s text. This updates the menu bar object in the Object Inspector dialog. You can also edit the menu’s properties in the Property Editor.
Figure 8-17

Creating menus and menu entries. Type Here placeholder (top left). Double-click the placeholder and enter the menu’s title (top right). Add a new menu entry (bottom left). New menu entry (bottom right)

From here, you can either add more menus, submenus, or actions. To add a submenu, first create a menu item. Then click on the plus symbol next to the new entry in the menu. This will add a new menu that branches off of the existing menu entry. Double-click on the Type Here placeholder and enter the text for the new item. Refer to Figure 8-18 for help.
Figure 8-18

Adding submenus. Click on the plus symbol next to the menu entry (left). Add new entry (right)

Adding Toolbars in Qt Designer

Toolbars can be added to the main window by right-clicking on the form to open a context menu. Click on the Add Tool Bar option.

The actions in toolbars are created as toolbar buttons and can be dragged between the menus and the toolbar. You can also add icons to the toolbar. This topic is covered in Display Images in Qt Designer. An example of the toolbar with an icon is shown in Figure 8-19.
Figure 8-19

Toolbar with Open File toolbar button

Adding Actions in Qt Designer

When items are first created in the menu and the toolbar, they are actually actions. Actions can be created, removed, given an icon, designated a shortcut hotkey, and made checkable all in the Action Editor dock widget (shown in Figure 8-7). Actions can also be shared between the menu and the toolbar.

To share an action between the menu and the toolbar so that both objects contain the same item, drag the action from the Action Editor that already exists in the menu onto the toolbar.

Displaying Images in Qt Designer

This section will take a quick look at how you can include images and icons in your application. Whether you are looking to add an image to a QLabel or trying to add icons to your toolbar, the process for adding an image is similar.

For example, if you have a QLabel widget on your form, you can access its properties in the Property Editor. Scroll down until you find the pixmap property. Click on its Value, and from here, you will be able to search for an image file. If you want to add an icon, then you will use the icon property, not pixmap.

You are given two options: Choose Resource… and Choose File…. If you have added resources to your project, then select Choose Resource…. Otherwise, you can search for images on your computer.
Figure 8-20

Add images to your application using the pixmap property

Adding Style Sheets in Qt Designer

Style sheets can also easily be added to each widget by right-clicking on a widget and selecting the Change styleSheet… option from the context menu. A dialog similar to Figure 8-21 will appear.
Figure 8-21

A dialog for creating style sheets

Here, you can use the drop-down arrows to select different properties and change colors, add resources, or change fonts.

That wraps up this chapter’s examination of Qt Designer.

Summary

Qt Designer is definitely a useful tool for creating GUI applications. It provides a drag-and-drop interface that makes it easier to organize widgets; modify the parameters of objects; create menus, toolbars, and dock widgets; add actions to menus; generate code that can be used in Python; and more. Qt Designer can make the design process much quicker and easier.

While this chapter covered a few of the basics for using Qt Designer, there are still other uses, such as creating your own custom widgets or building dialog boxes.

The following chapters will begin to look at more specific PyQt classes and topics that can be used to further improve user interfaces. In the next chapter, you will discover how to use the QClipboard class for copying and pasting data between different applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset