As you add more and more features to your applications, you will need some way to present all of the individual options to the user. A menu is a list of commands that a computer program can perform presented in a more manageable and organized fashion. No matter what type of device or application you are using or what kind of menu system it has, if it has a menu in place, its role is to help you navigate through the various operations in order to help you select the tasks you wish to perform.
Graphical user interfaces have numerous kinds of menus, such as context menus or pull-down menus, and can contain a variety of text and symbols. These symbols can be selected to give the computer an instruction. Think about a text editing program and all the various icons at the top, for example, open a file, save a file, select font, or select color. All of these symbols and text represent some task that the application can perform presented to the user in a manner that should promote better ease of use.
In this chapter we are going to take a look at how to create menus and toolbars for GUI applications in PyQt5. Everything up until now has been used to build a foundation for creating user interfaces, from PyQt classes and widgets to layout design.
Different from previous chapters, here we will be looking at how to make completely functioning programs, a notepad GUI and a simple photo editor GUI. These applications can either be used right away or as a starting point for building your own GUI program. There is a fair amount of information, from new concepts to additional widgets and classes, covered in this chapter.
- 1.
The QMainWindow class for setting up the main window
- 2.
Creating QMenubar and QMenu objects
- 3.
Adding actions to menus using the QAction class
- 4.
Setting up the status bar using QStatusBar to display information about actions
- 5.
Using QDockWidget to build detachable widgets to hold an application’s tools
- 6.
How to create submenus and checkable menu items
Setting and changing icons in the main window and on widgets with QIcon
New types of dialogs including QInputDialog, QColorDialog, QFontDialog, and QMessageBox’s About dialog box
How to handle and manipulate images using QPixmap and QTransform classes
How to print images using QPrinter and QPainter
Let’s jump right into coding a basic menu framework that will help you learn about creating menus with PyQt5 and some new classes, QMainWindow and QMenu.
Create a Basic Menu
Basic structure for creating the menu in an application
Explanation
The framework for this program contains no widgets, but does show how to set up a simple File menu located in the top-left corner of the GUI. Take a look at the beginning of the program and notice the classes being imported from QtWidgets. We still import QApplication, but there are also two new classes, QMainWindow and QAction. You may also notice that this time there is no QWidget.
The class to build our window inherits from QMainWindow instead of QWidget.
QMainWindow vs. QWidget
The QMainWindow class focuses on creating and managing the layout for the main window of an application. It allows you to set up a window with a status bar, a toolbar, dock widgets, or other menu options in predefined places all designed around functions that the main window should have.
The QWidget class is the base class for all user interface objects in Qt. The widget is the basic building block of GUIs. It is interactive, allowing the user to communicate with the computer to perform some task. Many of the widgets you have already looked at, such as QPushButton and QTextEdit, are just subclasses of QWidget that give functionality to your programs.
The central widget in the center of the window must be set if you are going to use QMainWindow as your base class. For example, you could use a single QTextEdit widget or create a QWidget object to act as a parent to a number of other widgets, then use setCentralWidget() , and set your central widget for the main window.
Creating the Menubar and Adding Actions
You could create a menubar by actually calling the QMenuBar class, but it is just as easy to create a menubar using the menuBar() function provided by QMainWindow.
Due to guidelines set by the MacOS system, you must set the property to use the platform’s native settings to False. Otherwise, the menu will not appear in the window. You can do this with menu_bar.setNativeMenuBar(False). For those using Windows or Linux, you can comment this line out or delete it completely from your code.
Here we are using the addMenu() method to add a menu named File to the menu_bar. Using addMenu() adds a QMenu object to our menubar. Once again, it is just as simple to use the functions provided by the QMainWindow class.
By default, on MacOS shortcuts are disabled. The best way to use them is with setShortcut().
Similar to QPushButtons, actions in the menu emit a signal and need to be connected to a slot in order to perform an action. This is done using triggered.connect() . Using the QAction class is very useful since many common commands can be invoked through the menu, toolbars, or shortcuts and need to be able to perform correctly no matter which widget invokes the action.
Setting Icons with the QIcon Class
In GUI applications, icons are small graphical images or symbols that can represent an action the user can perform. They are often used to help the user more quickly locate common actions and better navigate an application. For example, in a word editing program such as Microsoft Word, the toolbar at the top of the GUI contains a large amount of icons, each with icon and textual descriptions.
Chapter 2 briefly introduced the QPixmap class which is used for handling images. The QIcon class provides methods that can use pixmaps and modify their style or size to be used in an application. One really great use of QIcon is to set the appearance of an icon representing an action to active or disabled.
Setting icons is very useful not only for the actions in a toolbar but also for setting the application icon that is displayed in the title bar of the GUI window. Actions can be in four states, represented by icons: Normal, Disabled, Active, or Selected. QIcon can also be used when setting the icons on other widgets, as well.
Listing 5-2 shows how to reset the application icon displayed in the main window and how to set the icon on a QPushButton.
For MacOS users, the application window cannot be changed due to system guidelines. You should still take a look at this program though, as it also shows how to set icons for other widgets in PyQt.
Code to show how to set icons for the main window and on QPushButtons
Explanation
The preceding example contains a simple button that, when clicked, will select an image randomly from the images list.
Here, the icon for icon_button is chosen randomly and passed as an argument to be handled by QIcon. Calling the setIconSize() method on a widget can be used to change the size of the icon. PyQt will handle the sizing and style of the widget based on your parameters in the main window. The button is then connected to a slot that is used to change the icon.
Finally, the label and button widgets are arranged using QVBoxLayout and set as the main window’s layout.
Project 5.1 – Rich Text Notepad GUI
For the first project, let’s take a look at how to improve the notepad GUI we saw back in Chapter 4. It’s important to actually build a complete program to help you to learn how to make your own GUIs from start to finish.
This time we will add a proper menubar with menus and actions. The user will also have the ability to open and save their text, either as HTML or plain text, and edit the text’s font, color, or size to give more functionality and creativity to their notes.
Design the Rich Text Notepad GUI
Usually before creating interfaces, you should think about and map out what kind of functionality you want your application to have and what kind of widgets you might need in order to achieve those tasks.
For a text editing application, the layout is generally very basic – a menubar at the top of the window with different menus for the various functions and tools, and an area for displaying and editing text. For the text field, we will be using a QTextEdit widget which will also serve as the central widget for the QMainWindow object.
More Types of Dialog Boxes in PyQt
In this project there are a number of different dialog boxes native to PyQt that are used including QInputDialog, QFileDialog, QFontDialog, QColorDialog, and QMessageBox. Let’s take a moment to get familiar with some new types of dialog boxes and find out how to include them in our code.
The QInputDialog Class
QInputDialog is a native dialog box in PyQt that can be used to receive input from the user. The input is a single value that can be a string, a number, or an item from a list.
getMultiLineText() – Method to get a multiline string from the user
getInt() – Method to get an integer from the user
getDouble() – Method to get a floating-point number from the user
getItem() – Method to let the user select an item from a list of strings
The QFontDialog Class
In order to change the font if a new one has been chosen, use the setCurrentFont() method and change it to the new font.
The QColorDialog Class
The QColorDialog class creates a dialog box for selecting colors like the one in Figure 5-9. Selecting colors can be useful for changing the color of the text, a window’s background color, and many other actions.
The About Dialog Box
In many applications you can often find an About item in the menu. Clicking this item will open a dialog box that displays information about the application such as the software’s logo, title, latest version number, and other legal information.
Rich Text Notepad GUI Solution
Rich text notepad GUI code
Explanation
There are quite a few classes to import for the notepad application. From the QtWidgets module, we need to import QMainWindow and QAction for creating the menubar and menu items. We also need to include the different PyQt dialog classes such as QFileDialog and QInputDialog. From QtGui, which provides many of the basic classes for creating GUI applications, QIcon is used for handling icons, QTextCursor can be used to get information about the cursor in text documents, and QColor provides methods to create colors in PyQt.
Next, the notepadMenu() method sets up the menubar object along with the different menu items. The menu for the notepad application, which can be seen in Figure 5-10, contains four menus, File, Edit, Tools, and Help. Each menu is given its own menu items for the most part based on guidelines that we have come to expect from applications. For example, a general File menu creates actions that allow the user to open, save, import, export, or print files.
The open_act object is generated by the QAction class. QIcon is used to set an icon next to the action’s text in the menu. Then the action is given text to display, Open. Many of the actions in the notepad program are given a textual shortcut using setShortcut(). Finally, we connect the open_act signal that is produced when it is triggered to a slot, in this case the openFile() method. Other actions are created in a similar manner.
QTextEdit already has predefined slots, such as cut(), copy(), and paste(), to interact with text. For most of the actions in the Edit menu, their signals are connected to these special slots rather than creating new ones.
There are a number of functions that are called on when a menu item is clicked. Each one of them opens a dialog box and returns some kind of input from the user, such as a new file, text or background color, or a keyword from a text search using the QInputDialog class.
Project 5.2 – Simple Photo Editor GUI
With the introduction of smartphones that have the latest technology to take amazing photos, more pictures are taken and modified every day. However, not every picture is perfect as soon as it is taken and technology also gives us tools to edit those images to our liking. Some photo editors are very simple, allowing the user to rotate, crop, or add text to images. Others let the user change the contrast and exposure, reduce noise, or even add special effects.
Design the Photo Editor GUI
QDockWidget, QStatusBar, and More
The QDockWidget class
The QStatusBar class
Creating submenus
Creating checkable menu items
Code to demonstrate how to create dock widgets, status bars, and toolbars
Explanation
A few new classes from the QtWidgets module are imported including QStatusBar, QToolBar, and QDockWidget. Getting to learn a little bit about these classes will be useful for creating more complex GUIs.
The QStatusBar Class
At the bottom of the GUI in Figure 5-14, there is a horizontal bar with the text “Quit program” displayed inside of it. This bar is known as the status bar as is created from the QStatusBar class. Sometimes an icon’s or menu item’s function is not explicitly understood. This widget is very useful for displaying extra information to the user about the capabilities of an action.
The first time this method is called, it creates the status bar, and following calls will return the status bar object.
will display the text “Quit program” when the mouse is over the exit_act icon or menu command.
The QToolBar Class
When the user is performing a number of routine tasks, having to open up the menu to select an action multiple times can become tedious. Luckily, the QToolBar class provides ways to create a toolbar with icons, text, or standard Qt widgets for quick access to frequently used commands.
Toolbars are generally located under the menubar like in Figure 5-14, but can also be placed vertically or at the bottom of the main window above the status bar. Refer to the image in Figure 5-2 for an idea of arranging the different widgets in the main window.
You should set the size of the icons in the toolbar using the setIconSize() method with QSize() to avoid extra padding when PyQt tries to figure out the arrangement by itself.
If you need to add widgets in your toolbar, you should also use QAction to take advantage of the classes’ ability to handle multiple interface elements.
The QDockWidget Class
The QDockWidget class is used to create detachable or floating tool palettes or widget panels. Dock widgets are secondary windows that provide additional functionality to GUI windows.
LeftDockWidgetArea
RightDockWidgetArea
TopDockWidgetArea
BottomDockWidgetArea
In order to place multiple widgets inside the dock, you could use a single QWidget as the parent for multiple child widgets and arrange them using one of the layout mangers from Chapter 4. Then, pass that QWidget as the argument to setWidget().
In this application if the dock widget is closed, we cannot get it back. In the “Photo Editor GUI Solution,” we will take a look at how to use checkable menu items to hide or show the dock widget.
Creating Submenus with Checkable Menu Items
When an application becomes very complex and filled with actions, its menus can also begin to turn into a cluttered mess. Using submenus , we can organize similar categories together and simplify the menu system. Figure 5-15 displays an example of a submenu.
Here we first create the View menu and add it to the menubar. The appearance_submenu is then created and added to the View menu. Don’t forget to also add an action to the submenu using the addAction() method.
Then, when the action is clicked, it will send a signal and you can use a slot to check the state of the menu item, whether it is on or off. This could be useful for showing or hiding dock widgets or the status bar.
Photo Editor GUI Solution
Photo editor code
Once complete, your application should look similar to the one in Figure 5-12.
Explanation
The photo editor application imports an assortment of new classes from different modules. From QtWidgets there are two new classes, QDesktopWidget and QSizePolicy. The QDesktopWidget class is used to access information about the screen on your computer. We will use it later to learn how to center a GUI on your desktop. The QSizePolicy class is used for resizing widgets.
From the QtGui module , we use QPixmap for handling images, QTransform for performing transformations on images, and QPainter which is useful for drawing, painting, and printing.
QRect, from QtCore, is used for creating rectangles. This will be used in the printImage() method .
The QPrintSupport module and its classes provide cross-platform support for accessing printers and printing documents.
The window is initialized like before except this time the setFixedSize() method is used to set the window’s geometry so that it cannot be resized.
The File menu contains the Open, Save, Print, and Exit actions. Setting the setEnabled() method on the print_act to False shows a disabled menu item and icon in the toolbar. The print_act only becomes enabled after an image is opened in the openImage() method .
Handling Images in PyQt
When an image file is opened using QFileDialog, we create a QPixmap object using that image, and then setPixmap() is called on the image_label to scale and set the image in the QLabel widget. Finally, the label is set as the central widget in the main window and resized according to the parameters in the setSizePolicy() method . QPixmap and other classes to handle images are covered further in Chapter 9.
The QTransform class provides a number of methods to use transformations on images. The photo editor application provides five actions for manipulating images: Flip 90°, Flip 180°, Flip Horizontal, Flip Vertical, and Resize Half. Figure 5-16 displays an example of an image being rotated 90°.
The QPrinter Class
If you need to create a printing method for your applications, the photo editor includes a function adopted from the Qt document web site.1
Take a look at the code and the comments to see how to use the QPrinter class to set up the printer and QPainter to set up the PDF file to be printed.
Center GUI Application on Your Desktop
Summary
By taking you through some actual examples of programs with working menus, my hope is that you can see how many classes are working together just to make a single application. The examples in this chapter are by no means all that can be done with menus. There are still plenty of other ways to organize the actions and widgets in your own projects including context menus (often referred to as pop-up menus), tabbed widgets with the QToolBox class, stacked widgets using the QStackedWidget class, and more.
Chapter 5 focused on the QMainWindow class for integrating menus easily into GUIs. A menubar consists of several menus, each of which is broken down into several commands. Each of these commands could themselves also be checkable or even submenus. Toolbars are often composed of icons that allow the user to more easily locate commands. The QDockWidget class creates movable and floating widgets that can be used to hold a number of different tools, widgets, or commands. Finally, the status bar created from the QStatusBar class establishes a space to give further textual information about each of the menu items.
The class that acts like the glue to keep track of all the different functions and whether they have been triggered or not is the QAction class. The QAction class manages these actions to ensure that no matter where the action is triggered, whether from a menu, the toolbar, or from shortcut keys, the application can perform the next appropriate action.
In Chapter 6 we will see how to modify the appearance of widgets with style sheets and learn about how to create custom signals in PyQt.