The notepad application example runs without problems on my Raspberry Pi. But the menu bar shows no icons, just blank rectangles. They do work if I click on them. What could be the problem?
If you've tried running the Notepad example on a Raspberry Pi and noticed that all the menu icons show up as blank rectangles, the buttons themselves still work — you just can't see the images. This is almost always caused by relative image paths not pointing where you expect them to.
When you use a relative path like os.path.join('images', 'my-icon.png'), Python resolves that path based on the current working directory — that is, the folder you were in when you launched the script. On a Raspberry Pi, this working directory can vary depending on how you start the application. If you double-click a .desktop shortcut, open it from a file manager, or run it from a different terminal directory, the working directory might not be the folder where your script lives. That means QIcon ends up looking for the images folder in the wrong place, finds nothing, and shows a blank rectangle instead.
Confirming the problem
You can verify this is what's happening by checking whether a QIcon actually loaded an image. In notepad.py, find the __init__ method:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Add these lines right after:
icon = QIcon(os.path.join('images', 'blue-folder-open-document.png'))
print("availableSizes:", icon.availableSizes())
Run the application from a terminal and look at the output. If the icon loaded successfully, you'll see something like:
availableSizes: [PyQt5.QtCore.QSize(16, 16)]
If the list is empty:
availableSizes: []
that confirms QIcon couldn't find the file at the relative path.
Fixing the image paths
The most reliable fix is to build your image paths relative to the script file itself, rather than relying on the working directory. Python provides __file__, which always points to the location of the current script. You can use it to construct a stable base path.
At the top of your script (after your imports), add:
PyQt/PySide Development Services — Stuck in development hell? I'll help you get your project focused, finished and released. Benefit from years of practical experience releasing software with Python.
basedir = os.path.dirname(__file__)
This gives you the directory where notepad.py lives. Now, everywhere you create a QIcon with a relative path like this:
QIcon(os.path.join('images', 'blue-folder-open-document.png'))
Replace it with:
QIcon(os.path.join(basedir, 'images', 'blue-folder-open-document.png'))
Do this for every QIcon call in the file. The path will now always resolve correctly, no matter where you launch the script from.
Why this works
os.path.dirname(__file__) returns the absolute path to the folder containing your Python file. By joining this with the images subdirectory and the filename, you get a full, absolute path to each icon — something like /home/pi/notepad/images/blue-folder-open-document.png. This path doesn't depend on your terminal's current directory, so it works whether you run the script from the command line, a desktop shortcut, or a file manager.
A complete example
Here's what the relevant part of your script should look like after applying the fix:
import os
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QMainWindow, QApplication
basedir = os.path.dirname(__file__)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
file_menu = self.menuBar().addMenu("&File")
open_action = file_menu.addAction(
QIcon(os.path.join(basedir, 'images', 'blue-folder-open-document.png')),
"&Open"
)
save_action = file_menu.addAction(
QIcon(os.path.join(basedir, 'images', 'disk.png')),
"&Save"
)
# ... rest of your setup
app = QApplication([])
window = MainWindow()
window.show()
app.exec_()
With this change in place, your icons will display correctly on the Raspberry Pi — and on any other platform, regardless of how the application is started.