在 qss 定义中使用 FBS 的获取资源方法?

Using FBS's get resource method in qss definitions?

我有一个单独的 qss 样式表,其中包含我对整个应用程序的样式表定义。我需要添加一个关闭按钮作为背景图片,因为我找不到有关使用内置图标的文档。

customTabBar::close-button {
    padding: 0px;
    margin: 0px;
    border-radius: 2px;
    border-color: rgba(0, 0, 0, 50%);
    background-image: url(%(closeIcon)s);
    background-position: center center;
    background-repeat: none;
}

from fbs_runtime.application_context.PyQt5 import ApplicationContext

import qstylizer.parser


customIcons = {
    "customTabBar::closeButton.backgroundImage": f"url({app.get_resource('ui/close.png')})",
}

app = ApplicationContext()

with open(app.get_resource("app.qss"), "r") as stylesheet:
    css = qstylizer.parser.parse(stylesheet.read())
    for key, value in customIcons.items():
        property = key.split(".")
        css[property[0]][property[1]].setValue(value)
    app.app.setStyleSheet(css.toString())

文件存储在默认的fbs结构中,在 src/main/resource/base/ui/*.png

因为我不能使用带有花括号的 fstrings 作为 qt 的一部分。 使用 python 字符串格式,但由于我有一些 rgba 颜色值也包含 %,所以我不断收到关键错误。

因为我不能使用 %ages 或花括号,所以我想用 get_resource 构建一个 qproperty,但我不确定如何做。我需要我的 qss 交叉兼容并且无法逃脱我的花括号。

我的主要问题是当我使用 FBS 冻结将应用程序与 fbs 打包时图像将不可用

使用 python 格式化工具解析和修改 Qt 样式 Sheet 可能会很复杂,例如在您的情况下,您尝试格式化 (0, 0, 0, 50%) 会导致错误,所以我建议使用 qstylizer(python -m pip install qstylizer),这样可以方便的修改属性:

QTabBar::close-button {
    padding: 0px;
    margin: 0px;
    border-radius: 2px;
    border-color: rgba(0, 0, 0, 50%);
    background-position: center center;
    background-repeat: none;
}
import functools

from fbs_runtime.application_context.PyQt5 import ApplicationContext

import qstylizer.parser


customIcons = {
    "QTabBar.closeButton.backgroundImage": f"url({app.get_resource('ui/close.png')})",
}

app = ApplicationContext()

with open(app.get_resource("app.qss"), "r") as stylesheet:
    css = qstylizer.parser.parse(stylesheet.read())
    for key, value in customIcons.items():
        obj = functools.reduce(getattr, key.split("."), css)
        obj.setValue(value)
    app.app.setStyleSheet(css.toString())

更新:

正在分析 the source code

if key and key[0] not in ["Q", "#", "[", " "] and not <b>key.istitle()</b>:
    key = inflection.underscore(key)

似乎 class 是 TitleCase,所以一个可能的解决方案是将 class 的名称更改为 Customtabbar

Customtabbar::close-button {
    padding: 0px;
    margin: 0px;
    border-radius: 2px;
    border-color: rgba(0, 0, 0, 50%);
    background-position: center center;
    background-repeat: none;
}
app = ApplicationContext()

customIcons = {
    "Customtabbar::close-button": {
        "background-image": f"url({app.get_resource('ui/close.png')})"
    },
}

with open(app.get_resource("app.qss"), "r") as stylesheet:
    css = qstylizer.parser.parse(stylesheet.read())
    for qcls, value in customIcons.items():
        for prop, v in value.items():
            css[qcls][prop] = v
    app.app.setStyleSheet(css.toString())

根据 PEP,class 名称必须是 CapWords 所以我通过更改创建了一个分支:

qstylizer/style.py

if key and key[0] not in ["Q", "#", "[", " "] and not key.istitle():

来自

if key and key[0] not in ["Q", "#", "[", " "] and key != inflection.camelize(key):

现在接受符合 PEP8 的 classes 的名称。

CustomTabBar::close-button {
    padding: 0px;
    margin: 0px;
    border-radius: 2px;
    border-color: rgba(0, 0, 0, 50%);
    background-position: center center;
    background-repeat: none;
}
app = ApplicationContext()

customIcons = {
    "CustomTabBar::close-button": {
        "background-image": f"url({app.get_resource('ui/close.png')})"
    },
}

with open(app.get_resource("app.qss"), "r") as stylesheet:
    css = qstylizer.parser.parse(stylesheet.read())
    for qcls, value in customIcons.items():
        for prop, v in value.items():
            css[qcls][prop] = v
    app.app.setStyleSheet(css.toString())

更新2:

PR已经被接受,所以只需要更新库:python -m pip install qstylizer --upgrade

根据@eyllanesc 的建议,这是我的解决方案。 rcc 文件,

<RCC>
  <qresource>
    <file alias="closeIcon">close.png</file>
  </qresource>
</RCC>

shell命令,

pyrcc5 -o resources.py resources.rcc

这是样式 sheet。

TabBarPlus::close-button {
    background-image: url(:/closeIcon);
    padding: 0px;
    margin: 0px;
    border-radius: 2px;
    background-position: center center;
    background-repeat: none;
}