如何在PyInstaller的--onefile选项中使用resource_path和PyQt5通过样式表添加图标?

3

基本上我想做的是通过样式表(QSS)在组合框中添加一个向下箭头,以便我可以使用PyInstaller的--onefile选项将py文件打包成一个文件: 代码如下,但似乎不起作用:

QComboBox::drop-down{
    image: url(resource_path("icon_example.png"))
}

resource_path 方法是:

def resource_path(self,relative_path):
    try:
       base_path = sys._MEIPASS
     except Exception:
       base_path = os.path.abspath(".")
     return os.path.join(base_path, relative_path)

1
提供一个[MRE]。 - eyllanesc
3个回答

0

这是一个老话题,但我的答案可能对其他人有用(受https://forum.qt.io/topic/17318/solved-using-variables-in-style-sheets-qss/11的启发)

如上所述,*.spec文件必须包含指向要包含在*.exe中的文件的链接:

added_files = [
    ( './images', 'images' ),
    ( './fonts', 'fonts' )
]

a = Analysis(['MyScript.py'],
             [...]
             datas=added_files
             [...]

获取相对路径的函数:
def relative_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

然后通过变量(相对路径)iconExample替换styleSheet中的文本“iconExample”:

iconExample = relative_path("./images/icon_example.png")).replace("\\", "/")

styleSheet = '''
QComboBox::drop-down{
    image: url(iconExample);
}
'''
styleSheet = styleSheet.replace("iconExample", iconExample)
myWidget.setStyleSheet(styleSheet)

我不知道它是不是最好的解决方案,但是它能正常运行。


0

在 qss 的 url 引用中,您应该使用绝对路径。您可以使用一个函数来替换该路径内容,然后将您的图标路径配置到 .spec 文件中的 *.exe 中。

例如,在 qss 文件中:

QComboBox::down-arrow
{
    image: url(QSS/QSS_IMG/arrow-down.png);
    width: 8px;
    height: 8px;
}


def replace_qss_path(content: str)->str:
    base_path = getattr(sys,"_MEIPASS",os.path.abspath(os.path.join(os.path.dirname(
    os.path.abspath(__file__)))))
    p = re.compile("url *[(](.*?)[)]", re.S)
    c_l = re.findall(p, content)
    for item in c_l:
        if not item.startswith(":"):
            content = content.replace(item, os.path.join(base_path, item).replace("\\","/"))
    return content

def get_qss():
    with open(resource_path("QSS/Integrid.qss"), "r", encoding="utf-8") as f:
        content = f.read()
        return replace_qss_path(content)


class MainWindow(QtWidgets.QMainWindow, Ui_MainWin):
    def __init__(self) -> None:
        super().__init__()
        self.setupUi(self)
        self.setStyleSheet(get_qss())

在 main.spec 文件中:

datas=[("E:/QSS/Integrid.qss", "QSS"),
 ("E:/QSS/QSS_IMG/*","QSS/QSS_IMG")
 ]

0
以下是我使用的代码,它完美地运行了。
import sys
from os.path import join, abspath
def resource_path(relative_path):
    if hasattr(sys, '_MEIPASS'):
        return join(sys._MEIPASS, relative_path)
    return join(abspath("."), relative_path)

请在spec文件中添加以下代码:
a.datas += [ ('back.png', 'icon/back.png', 'DATA')]

其中'back.png'是我的图像路径,将保存在pyinstaller exe包中,而'icon/back.png'是我在打包之前将图像文件放置在icon文件夹中的路径。

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['main.py'],
             pathex=['C:\\Users\\User\\Documents\\GitHub\\Mypath'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=['mkl','whl'],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)

a.datas += [ ('back.png', 'icon/back.png', 'DATA')]
a.datas += [ ('main.ico', 'icon/main.ico', 'DATA')]
a.datas += [ ('folder.png', 'icon/folder.png', 'DATA')]
a.datas += [ ('download.png', 'icon/download.png', 'DATA')]

pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True , icon='icon\\main.ico')

然后你可以像这样调用你的图片:resource_path('download.png')


我想给你答案,但你没有回答100%。比如说,我该如何在样式表中使用resource_path。这就是我的问题所在。 - mrgatos
只需将其用作您问题中的代码,使用 resource_path("icon_example.png") 作为图像路径。 - Jim Chen
最重要的部分是您应该在spec文件中添加a.datas += [ ('icon_example.png', 'yourPath/icon_example.png', 'DATA')],这样在捆绑您的py文件后,您就可以使用resource_path来调用您的图像。 - Jim Chen
resource_path 在普通的 Python 代码中可以正常工作,但即使在 spec 文件中添加文件,它在样式表代码中也无法正常工作。图像不会在样式表中加载。 - mrgatos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接