Using FBS's get resource method in qss definitions?

264 views Asked by At

I have a seperate qss stylesheet that contains my stylesheet definitions for my entire app. I need to add a close button as background image since I couldnt find documentation on using inbuilt icons.

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())

the files are stored in the default fbs structure, under src/main/resource/base/ui/*.png

since I cannot use fstrings with curly braces being a part of qt. And this answer using python string formatting, but I keep getting key errors due to me having some rgba color values that also have % in it.

Since I cant use %ages or curly braces, I was thinking of building a qproperty out of get_resource, but I am not sure how. I need my qss cross compatible and cannot escape my curly braces.

My main problem is that the image wont be available when I package the application wtih fbs, using FBS freeze

2

There are 2 answers

0
Blaine On BEST ANSWER

As per @eyllanesc 's suggestion, this was my solution. the rcc file,

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

the shell command,

pyrcc5 -o resources.py resources.rcc

and here is the style sheet.

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

Parsing and modifying Qt Style Sheet using the python formatting tools can be complicated, for example in your case you try to format (0, 0, 0, 50%) causing errors, so I recommend using qstylizer(python -m pip install qstylizer), so you can easily modify the properties:

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())

Update:

Analyzing the source code:

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

it seems that the classes are TitleCase so a possible solution is to change the name of the class to 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())

According to PEP the class names must be CapWords so I have created a fork by changing:

qstylizer/style.py

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

by

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

Now accept the names of the classes that comply with PEP8.

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())

Update2:

The PR has been accepted so it is only necessary to update the library: python -m pip install qstylizer --upgrade.