When it comes to developing graphical user interface (GUI) applications with Python and PyQt, some of the most useful and versatile graphical elements that you’ll ever use are menus, toolbars, and status bars.
Menus and toolbars can make your applications look polished and professional, presenting users with an accessible set of options, while status bars allow you to display relevant information about the application’s status.
In this tutorial, you’ll learn:
- What menus, toolbars, and status bars are
- How to create menus, toolbars, and status bars programmatically
- How to populate Python menu and toolbar using PyQt actions
- How to use status bars to display status information
In addition, you’ll learn some programming best practices that you can apply when creating menus, toolbars, and status bars with Python and PyQt. If you’re new to GUI programming with PyQt, then you can check out Python and PyQt: Building a GUI Desktop Calculator.
You can download the code and resources for the sample application that you’ll build in this tutorial by clicking on the box below:
Download the sample code: Click here to get the code you’ll use to learn how to add menus, toolbars, and status bars to your GUI applications using Python and PyQt.
Using Icons and Resources in PyQt
The Qt library includes the Qt resource system, which is a convenient way of adding binary files such as icons, images, translation files, and other resources to your applications.
To use the resource system, you need to list your resources in a resource collection file, or a .qrc
file. A .qrc
file is an XML
file that contains the location, or path, of each resource in your file system.
Suppose that your sample application has a resources
directory containing the icons that you want to use in the application’s GUI. You have icons for options like New, Open, and so on. You can create a .qrc
file containing the path to each icon:
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="file-new.svg">resources/file-new.svg</file>
<file alias="file-open.svg">resources/file-open.svg</file>
<file alias="file-save.svg">resources/file-save.svg</file>
<file alias="file-exit.svg">resources/file-exit.svg</file>
<file alias="edit-copy.svg">resources/edit-copy.svg</file>
<file alias="edit-cut.svg">resources/edit-cut.svg</file>
<file alias="edit-paste.svg">resources/edit-paste.svg</file>
<file alias="help-content.svg">resources/help-content.svg</file>
</qresource>
</RCC>
Each <file>
entry must contain the path to a resource in your file system. The specified paths are relative to the directory containing the .qrc
file. In the above example, the resources
directory needs to be in the same directory as the .qrc
file.
alias
is an optional attribute that defines a short alternative name that you can use in your code to get access to each resource.
Once you have the resources for your application, you can run the command-line tool pyrcc5
targeting your .qrc
file. pyrcc5
is shipped with PyQt and must be fully functional on your Python environment once you have PyQt installed.
pyrcc5
reads a .qrc
file and produces a Python module that contains the binary code for all your resources:
$ pyrcc5 -o qrc_resources.py resources.qrc
This command will read resources.qrc
and generate qrc_resources.py
containing the binary code for each resource. You’ll be able to use those resources in your Python code by importing qrc_resources
.
Note: If something goes wrong when running pyrcc5
, then make sure that you’re using the right Python environment. If you install PyQt in a Python virtual environment, then you won’t be able to use pyrcc5
from outside that environment.
Here’s a fragment of the code in qrc_resources.py
that corresponds to your resources.qrc
:
# -*- coding: utf-8 -*-
# Resource object code
#
# Created by: The Resource Compiler for PyQt5 (Qt v5.9.5)
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore
qt_resource_data = b"\
\x00\x00\x03\xb1\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
...
With qrc_resources.py
in place, you can import it into your application and refer to each resource by typing a colon (:) and then either its alias
or its path. For example, to access file-new.svg
with its alias, you would use the access string ":file-new.svg"
. If you didn’t have an alias
, you would access it by its path with the access string ":resources/file-new.svg"
.
If you have aliases, but for some reason you want to access a given resource by its path instead, then you might have to remove the colon from the access string in order to make this work properly.
To use the icons in your actions, you first need to import your resources module:
import qrc_resources
Once you’ve imported the module that contains your resources, you can use the resources in your application’s GUI.
Note: Linters, editors, and IDEs may flag the above import statement as unused because your code won’t include any explicit use of it. Some IDEs may go even further and remove that line automatically.
In these situations, you must override the suggestions of your linter, editor, or IDE and keep that import in your code. Otherwise, your application won’t be able to display your resources.
To create an icon using the resources system, you need to instantiate QIcon
, passing the alias or the path to the class constructor:
newIcon = QIcon(":file-new.svg")
In this example, you create a QIcon
object with the file file-new.svg
, which is in your resources module. This provides a convenient way of using icons and resources throughout your GUI application.
Now go back to your sample application and update the last line of ._createMenuBar()
:
from PyQt5.QtGui import QIcon
import qrc_resources
# Snip...
class Window(QMainWindow):
# Snip...
def _createMenuBar(self):
menuBar = self.menuBar()
# Using a QMenu object
fileMenu = QMenu("&File", self)
menuBar.addMenu(fileMenu)
# Using a title
editMenu = menuBar.addMenu("&Edit")
# Using an icon and a title
helpMenu = menuBar.addMenu(QIcon(":help-content.svg"), "&Help")
For this code to work, you first need to import QIcon
from PyQt5.QtGui
. You also need to import qrc_resources
. In the last highlighted line, you add an icon to helpMenu
using help-content.svg
from your resources module.
If you run your sample application with this update, then you’ll get the following output:

The application’s main window now shows an icon on its Help menu. When you click the icon, the menu shows the text Help
. Using icons in a menu bar isn’t a common practice, but PyQt allows you to do it anyway.
Adding Options to a Toolbars in PyQt
Toolbars are a quite useful component when it comes to building GUI applications with Python and PyQt. You can use a toolbar to present your users with a quick way to get access to the most commonly used options in your application. You can also add widgets like spin boxes and combo boxes to a toolbar for allowing the user to directly modify some properties and variables from the application’s GUI.
In the following few sections, you’ll learn how to add options or buttons to your toolbars using actions and also how to add widgets to a toolbar with .addWidget()
.
Populating Toolbars With Actions
To add options or buttons to a toolbar, you need to call .addAction()
. In this section, you’ll rely on the variation of .addAction()
that QToolBar
inherits from QWidget
. So, you’ll call .addAction()
with an action as an argument. This will allow you to share your actions between menus and toolbars.
When you’re creating toolbars, you’ll commonly face the problem of deciding what options to add to them. Typically, you’ll want to add only the most frequently used actions to your toolbars.
If you return to your sample application, then you’ll remember that you added three toolbars:
- File
- Edit
- Help
In the File toolbar, you can add options like the following:
- New
- Open
- Save
In the Edit toolbar, you can add the following options:
- Copy
- Paste
- Cut
Normally, when you want to add buttons to a toolbar, you first select the icons that you want to use on each button. This isn’t mandatory, but it’s a best practice. Once you’ve selected the icons, you need to add them to their corresponding actions.
Here’s how you can add icons to the actions of your sample application:
class Window(QMainWindow):
# Snip...
def _createActions(self):
# File actions
self.newAction = QAction(self)
self.newAction.setText("&New")
self.newAction.setIcon(QIcon(":file-new.svg"))
self.openAction = QAction(QIcon(":file-open.svg"), "&Open...", self)
self.saveAction = QAction(QIcon(":file-save.svg"), "&Save", self)
self.exitAction = QAction("&Exit", self)
# Edit actions
self.copyAction = QAction(QIcon(":edit-copy.svg"), "&Copy", self)
self.pasteAction = QAction(QIcon(":edit-paste.svg"), "&Paste", self)
self.cutAction = QAction(QIcon(":edit-cut.svg"), "C&ut", self)
# Snip...
To add icons to your actions, you update the highlighted lines. In the case of newAction
, you use .setIcon()
. In the rest of the actions, you use the constructor with an icon
, a title
, and a parent
object as arguments.
Once your selected actions have icons, you can add these actions to their corresponding toolbar by calling .addAction()
on the toolbar object:
class Window(QMainWindow):
# Snip...
def _createToolBars(self):
# File toolbar
fileToolBar = self.addToolBar("File")
fileToolBar.addAction(self.newAction)
fileToolBar.addAction(self.openAction)
fileToolBar.addAction(self.saveAction)
# Edit toolbar
editToolBar = QToolBar("Edit", self)
self.addToolBar(editToolBar)
editToolBar.addAction(self.copyAction)
editToolBar.addAction(self.pasteAction)
editToolBar.addAction(self.cutAction)
With this update to ._createToolBars()
, you add buttons for the New, Open, and Save options to the File toolbar. You also add buttons for the Copy, Paste, and Cut options to the Edit toolbar.
Note: The order in which buttons are displayed on a toolbar from left to right corresponds to the order in which you add the buttons in your code.
If you run your sample application now, then you’ll get the following window on your screen:

The sample application now shows two toolbars with a few buttons each. Your users can click these buttons to get quick access to the application’s most commonly used options.
Note: When you first wrote ._createToolBars()
back in the section Creating Toolbars, you created a Help toolbar. This toolbar was intended to show how to add a toolbar using a different variation of .addToolBar()
.
In the above update of ._createToolBars()
, you get rid of the Help toolbar just to keep the example short and clear.
Note that, since you share the same actions between your menus and toolbars, the menu options will also display the icons on their left side, which is a big win in terms of productivity and resource use. This is one of the advantages of using PyQt actions to create menus and toolbars with Python.
Adding Widgets to a Toolbar
In some situations, you’ll find it useful to add specific widgets like spin boxes, combo boxes, or others to a toolbar. A common example of this is the combo boxes that most word processors use to allow the user to change the font of a document or the size of a selected text.
To add widgets to a toolbar, you first need to create the widget, setup its properties and then call .addWidget()
on the toolbar object passing the widget as an argument.
Suppose you want to add a QSpinBox
object to the Edit toolbar of your sample application to allow the user to change the size of something, which could be the font size. You need to update ._createToolBars()
:
from PyQt5.QtWidgets import QSpinBox
# Snip...
class Window(QMainWindow):
# Snip...
def _createToolBars(self):
# Snip...
# Adding a widget to the Edit toolbar
self.fontSizeSpinBox = QSpinBox()
self.fontSizeSpinBox.setFocusPolicy(Qt.NoFocus)
editToolBar.addWidget(self.fontSizeSpinBox)
Here, you first import the spin box class. Then you create a QSpinBox
object, set its focusPolicy
to Qt.NoFocus
, and finally add it to your Edit toolbar.
Note: In the above code, you set the focusPolicy
property of the spin box to Qt.NoFocus
because if this widget gets the focus, then the application’s keyboard shortcuts won’t work properly.
Now, if you run the application, then you’ll get the following output:

Here, the Edit toolbar shows a QSpinBox
object that your users can use to set the size of the font or any other numeric property on your application.
Customizing Toolbars
PyQt toolbars are quite flexible and customizable. You can set a bunch of properties on a toolbar object. Some of the most useful properties are shown in the following table:
Property | Feature Controlled | Default Setting |
---|---|---|
allowedAreas |
The toolbar areas in which you can place a given toolbar | Qt.AllToolBarAreas |
floatable |
Whether you can drag and drop the toolbar as an independent window | True |
floating |
Whether the toolbar is an independent window | True |
iconSize |
The size of the icons displayed on the toolbar buttons | Determined by the application’s style |
movable |
Whether you can move the toolbar within the toolbar area or between toolbar areas | True |
orientation |
The orientation of the toolbar | Qt.Horizontal |
All these properties have an associated setter method. For example, you can use .setAllowedAreas()
to set allowedAreas
, .setFloatable()
to set floatable
, and so on.
Now, suppose you don’t want your users to move the File toolbar around the window. In this case, you can set movable
to False
using .setMovable()
:
class Window(QMainWindow):
# Snip...
def _createToolBars(self):
# File toolbar
fileToolBar = self.addToolBar("File")
fileToolBar.setMovable(False)
# Snip...
The highlighted line makes the magic here. Now your users can’t move the toolbar around the application’s window:

The File toolbar doesn’t show the double dotted line anymore, so your users won’t be able to move it. Note that the Edit toolbar is still movable. You can change other properties on your toolbars using this same approach and customize them according to your needs.
Building Python Status Bars in PyQt
A status bar is a horizontal panel that is usually placed at the bottom of the main window in a GUI application. Its primary purpose is to display information about the current status of the application. The status bar can also be divided into sections to show different information on each section.
According to the Qt documentation, there are three types of status indicators:
-
Temporary indicators take up almost the entire status bar for a short time to display tooltip texts, menu entries, and other time-sensitive information.
-
Normal indicators take up a part of the status bar and display information that users may want to reference periodically, such as word counts in a word processor. These may be briefly hidden by temporary indicators.
-
Permanent indicators are always displayed in the status bar, even when a temporary indicator is activated. They’re used to show important information about the current mode of the application, such as when the Caps Lock key has been pressed.
You can add a status bar to your main window–style application using one of the following options:
-
Call
.statusBar()
on yourQMainWindow
object..statusBar()
creates and returns an empty status bar for the main window. -
Create a
QStatusBar
object, then call.setStatusBar()
on your main window with the status bar object as an argument. That way,.setStatusBar()
will set your status bar object as the main window’s status bar.
Here you have two alternative implementations for adding a status bar to your sample application:
# 1. Using .statusBar()
def _createStatusBar(self):
self.statusbar = self.statusBar()
# 2. Using .setStatusBar()
def _createStatusBar(self):
self.statusbar = QStatusBar()
self.setStatusBar(self.statusbar)
Both implementations produce the same result. However, most of the time you’ll use the first implementation for creating your status bars. Note that for the second implementation to work, you need to import QStatusBar
from PyQt5.QtWidgets
.
Add one of the above implementations to your application’s Window
and then call ._createStatusBar()
in the class initializer. With these additions, when you run your application again, you’ll see a window like this:

Your application now has a status bar at the bottom of its main window. The status bar is almost invisible, but if you look closely, then you’ll notice a small dotted triangle on the bottom-right corner of the window.
Showing Temporary Status Messages
The main purpose of a status bar is to present status information to the users of your application. To show temporary status messages in a status bar, you need to use QStatusBar.showMessage()
. This method takes the following two arguments:
message
holds a status indicator message as a string.timeout
holds the number of milliseconds that the message will be shown on the status bar.
If timeout
is 0
, which is its default value, then the message remains on the status bar until you call .clearMessage()
or .showMessage()
on the status bar.
If there’s an active message on your status bar and you call .showMessage()
with a new message, then the new message will obscure or replace the old one.
Go to your sample application and add the following line to ._createStatusBar()
:
class Window(QMainWindow):
# Snip...
def _createStatusBar(self):
self.statusbar = self.statusBar()
# Adding a temporary message
self.statusbar.showMessage("Ready", 3000)
The final line in ._createStatusBar()
will make your application show a Ready
message on the application’s status bar for 3000
milliseconds:

When you run the application, the status bar shows the message Ready
. After 3000
milliseconds, the message disappears and the status bar gets cleared and ready to show a new status message.
Showing Permanent Messages in Status Bars
You can also show permanent messages on your application’s status bar. A permanent message keeps the user informed about some general state of the application. For example, in a text editor, you might want to show a permanent message with information about the text encoding of the currently opened file.
To add permanent messages to your status bars, you use a QLabel
object to hold the message. Then you add the label to the status bar by calling .addPermanentWidget()
. This method permanently adds the given widget to the current status bar. The widget’s parent is set to the status bar.
.addPermanentWidget()
takes the following two arguments:
widget
holds the widget object that you want to add to the status bar. Some commonly used widgets on this role areQLabel
,QToolButton
, andQProgressBar
.stretch
is used to compute a suitable size for the widget as the status bar grows and shrinks. It defaults to0
, which means that the widget is going to take the minimum amount of space.
Keep in mind that a permanent widget won’t be obscured or replaced by temporary messages. .addPermanentWidget()
locates widgets at the right side of the status bar.
Note: You can use .addPermanentWidget()
not only to show permanent messages on your status bars but also to present the user with a progress bar to monitor the duration of a given operation. You can also provide buttons on the status bar to allow the user to change properties like the file encoding on a text editor.
When you use these kinds of widgets on a status bar, try to stick to the most commonly used widget for the type of application that you’re developing. This way, your users will feel right at home.
Say you want to turn your sample application into a text editor, and you want to add a message to the status bar that shows information about the word count of the current file. To do that, you can create a method called .getWordCount()
and then add a permanent message using .addPermanentWidget()
and a QLabel
object:
class Window(QMainWindow):
# Snip...
def getWordCount(self):
# Logic for computing the word count goes here...
return 42
This method adds the logic for computing the word count in the currently opened document. Now, you can show this information as a permanent message:
class Window(QMainWindow):
# Snip...
def _createStatusBar(self):
self.statusbar = self.statusBar()
# Adding a temporary message
self.statusbar.showMessage("Ready", 3000)
# Adding a permanent message
self.wcLabel = QLabel(f"{self.getWordCount()} Words")
self.statusbar.addPermanentWidget(self.wcLabel)
In the last two lines, you first create a QLabel
object (wcLabel
) to hold the message about the word count. To create the message, you use an f-string, in which you insert a call to .getWordCount()
to get the word count information. Then you add the label to the status bar using .addPermanentWidget()
.
In this case, you create the QLabel
object as an instance attribute because the word count needs to be updated according to the changes that the user makes to the current file.
If you run the application with this update, then you’ll see the word count message on the right side of the status bar:

The status bar shows a message that informs the user about the word count in a hypothetical current file. The ability to present the user with permanent information or other options in the status bar is quite useful and can help you to greatly improve the user experience for your applications.
Adding Help Tips to Actions
When it comes to creating GUI applications, it’s important to offer help tips to your users about specific functionalities on the application’s interface. Help tips are short messages that provide a quick guide to the user about some of the options that the application offers.
PyQt actions allow you to define the following kinds of help tips:
-
Status tips are help tips that the application shows on the status bar when the user hovers the mouse pointer over a menu option or a toolbar button. By default, a status tip contains an empty string.
-
Tooltips are help tips that the application shows as floating messages when the user hovers their mouse pointer over a toolbar button or widget. By default, a tooltip contains text that identifies the action at hand.
Note: PyQt also offers the What’s This help tip that you can use in widgets and actions to show a richer description of the functionality that the widget or action provides. However, this topic is beyond the scope of this tutorial.
To learn how help tips work, you can add some status tips and tooltips to your sample application. Go to ._createActions()
and add the following lines of code:
class Window(QMainWindow):
# Snip...
def _createActions(self):
# File actions
# Snip...
self.saveAction.setShortcut("Ctrl+S")
# Adding help tips
newTip = "Create a new file"
self.newAction.setStatusTip(newTip)
self.newAction.setToolTip(newTip)
# Edit actions
self.copyAction = QAction(QIcon(":edit-copy.svg"), "&Copy", self)
# Snip...
The three highlighted lines set the message "Create a new file"
as the status and tooltip for the New option. If you run the application now, then you’ll see that the New option shows a short but descriptive help tip to the user:

When you click the File menu and hold your mouse pointer on New, you can see the help tip message shown on the left side of the status bar. On the other hand, if you move the mouse pointer over the New toolbar button, then you can see the message on the status bar and also as a small floating box next to the mouse pointer.
In general, adding help tips to your Python menus and toolbars is considered a best practice. It will make your GUI applications easier for users to navigate and learn. As a final exercise, you can continue adding help tips to the rest of the actions of your sample application and see how it looks after you’re done.
Conclusion
Menus, toolbars, and status bars are common and important graphical components of most GUI applications. You can use them to provide your user with a quick way to access the application’s options and functionalities. They also make your applications look polished and professional and provide a great experience to your users.
In this tutorial, you’ve learned how to:
- Programmatically create menus, toolbars, and status bars
- Use PyQt actions to populate your menus and toolbars
- Provide status information by using a status bar
Along the way, you’ve learned some best programming practices that are worth considering when it comes to adding and using menus, toolbars, and status bars in your GUI applications.
You’ve also coded a sample application in which you applied all your knowledge on menus and toolbars. You can get the full source code and other resources for that application by clicking on the box below:
Download the sample code: Click here to get the code you’ll use to learn how to add menus, toolbars, and status bars to your GUI applications using Python and PyQt.