0

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.

  1. When I provide the absolute path (as shown in the code), the icon works with python but not when compiled with PyInstaller
  2. 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?

  1. The first time: pyinstaller mycode.py
  2. Then I edited the spec file and added the svg file into datas
  3. 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

picture of file structure

ChaserAide
  • 111
  • 1
  • 7
  • How do you run pyinstaller? How do you run the .exe? – eyllanesc Dec 06 '19 at 22:10
  • I have one more question: Are there files next to the .exe? If there are then what are they? – eyllanesc Dec 06 '19 at 23:04
  • Answers were updated into the post – ChaserAide Dec 07 '19 at 00:07
  • I guess in the icons folder of dist/codeSample is the .svg. mmm, I recommend using fbs which is a tool that allows you to pack PyQt5. – eyllanesc Dec 07 '19 at 00:10
  • 1
    try with this script: https://gist.githubusercontent.com/eyllanesc/02dbe6efff645fcb283c45b96497cd32/raw/7df279619119d091c9455efb36f0c0af28206b21/codeSample.py and check if the 4th option of the QComboBox is the path of the .svg – eyllanesc Dec 07 '19 at 00:20
  • Thank you @eyllanesc, the (%s) part worked. What is that called (so I can understand it better for the future). Also, the `combo.addItem` part was unnecessary because it just added the path to he dropdown list. – ChaserAide Dec 07 '19 at 00:42
  • 1
    1) "%s" is used to concatenate. See https://stackoverflow.com/questions/997797/what-does-s-mean-in-a-python-format-string 2) I wanted to take the opportunity to test if the "%s" option failed. – eyllanesc Dec 07 '19 at 00:45

1 Answers1

0

I know it's an old question, but I had problems with Pyinstaller showing images and StyleSheets. I solved the problem using '.png' images instead of '.svg' images.

Guest
  • 1