I am writing a Python program that uses PyQt for the UI. When I run it with python, the QComboBox icon is shown, as expected. However, after I compile it using PyInstaller and run the program I get an error (see below) and then the icon is not shown.
What I have tried
- You'll see in my spec file that I've put the file path inside 'datas'.
- You'll see in my code that I have the necessary resource_path function. In the larger program, I used it successfully to connect with a SQLite database.
Weird Issue
The icon is the Image in the QComboBox::down-arrow
selector in the stylesheet.
- When I provide the absolute path (as shown in the code), the icon works with python but not when compiled with PyInstaller
- When I provide the path using resource_path(), the icon doesn't work at all.
How do I make this icon show after using PyInstaller?
Error
qt.svg: Cannot open file '/Users/user.name/icons/wd-icon-prompts.svg', because: No such file or directory
Code
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
# QT Layout Doc: https://doc.qt.io/qt-5/layout.html
# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Example")
# label = QLabel("This is a PyQt5 window!")
combo = QComboBox()
combo.addItems(['Item 1', 'Item 2', 'Item 3'])
self.setCentralWidget(combo)
styleSheet = """
QComboBox {
background-color: #fff;
border: 1px solid #ced3d9;
border-radius: 3px;
color: #333333;
font: 14px;
height: 36px;
padding: 1px 0px 1px 3px;
padding: ;
margin: 50px;
min-width: 300px;
selection-background-color: #e8ebed;
}
QComboBox:editable {
background: #fff;
}
QComboBox::drop-down {
background: #fff;
border: 0;
subcontrol-origin: padding;
subcontrol-position: right;
width: 25px;
}
QComboBox::down-arrow {
image: url(icons/wd-icon-prompts.svg);
width: 26px;
height: 26px;
padding: 25px;
}
QComboBox::down-arrow:active {
}
QComboBox QAbstractItemView {
background: white;
}
"""
self.setStyleSheet(styleSheet)
def resource_path(self,relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.environ.get("_MEIPASS2",os.path.abspath("."))
return os.path.join(base_path, relative_path)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
Spec File
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['codeSample.py'],
pathex=['/Users/user.name/Desktop/SoapDayCode copy'],
binaries=[],
datas=[('icons/wd-icon-prompts.svg', 'icons')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='codeSample',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='codeSample')
EDITS:
Question 1) How do you run pyinstaller?
- The first time:
pyinstaller mycode.py
- Then I edited the spec file and added the svg file into datas
- From now on when troubleshooting:
pyinstaller mycode.spec
Question 2) How do you run the .exe?
- After compiling, I navigate to /dist/mycode/ and find the exe called mycode. I double click mycode
Question 3) Are there files next to the .exe? If there are then what are they?
Yes, there are many because I did not use the onefile option. Here's a picture