[Solved]Select QListWidgetItem with css property selector.



  • Hello,

    I can't seem to be able to select QListWidget items using the usual css selectors. From what I understand, they should work on any QWidget. For example, these don't work:

    * [text="Blee"] { /* genius stuff like gradients and whatnot */ }
    QListWidget::item[text="Blooouuuu"] { /* much sadness was had */}
    

    I'm not sure how else I could access a specific element of a pre-made QListWidget. I need to change the icons using css. I can't do it with c++, though I have access to the code base, so I could hack something in to get the css icon change working.

    Thank you for any help.

    P.S. Brain too dead to try and make jokes, here.



  • Can anyone at least confirm this is not possible and why? So I stop wasting time on this :/


  • Lifetime Qt Champion

    Hi,

    Can you provide a minimal sample code that shows the (mis)behavior ?



  • Well the QWidgetList is created 100% in Qt designer. Inside there are items, with icons, and I am just trying to get at a specific item (not even changing anything yet).

    For example:

    QListWidget::item[text="blee"] {
        color: red;
        background: white;
        border: none;
    }
    

    Nothing happens. I can't seem to be able to select a specific item inside the QWidgetList :/

    edit: Here is the QWidgetList setup http://imgur.com/fBp0zp0

    edit2: The project is open-source, so if you really want to look into what is going on I can send you to my github branch. Though I don't see anything special going on here. The item is a QWidget but seems to have no name, no way to set a name... Other than maybe editing the ui xml manually.


  • Lifetime Qt Champion

    I just realized something: a QListWidget item is not a QObject, so it doesn't have any property that you can use here.

    So currently you might have to do a minimum of C++. Depending on what you have access to or you're allowed to modify, a QStyledItemDelegate could do the job



  • Yes, that's kind of stupid and feels more like an oversight than anything else. Anyways, my solution:
    Parse the qss file yourself, use fake ids and a style that doesn't break Qt parser, tell users to copy paste the css as is. In your software, add the icons statically to the class you want and in the constructor call a setter method for the stored icons.

    C++, parse the CSS

    void OBSApp::setThemeSettingsIcons(QString filepath)
    {
        // This method relies on the fact the settings order will not change.
        QStringList icons = { "#GeneralIcon", "#StreamIcon", "#OutputIcon",
                "#AudioIcon", "#VideoIcon", "#AdvancedIcon"};
    
        QFile file(filepath);
        if(!file.open(QIODevice::ReadOnly)) {
            blog(LOG_ERROR, "File error %s, %s",
                    file.errorString().toStdString().c_str(),
                    filepath.toStdString().c_str());
            return;
        }
        QFileInfo info(file);
        filepath = info.canonicalPath() + "/";
        QTextStream in(&file);
    
        while(!in.atEnd()) {
            QString line = in.readLine();
    
            // Minimize the number of lines we check.
            if (!line.startsWith("#"))
                continue;
    
            int row = 0;
            for (auto x : icons) {
                // Find an icon.
                if (!line.startsWith(x)) {
                    row++;
                    continue;
                }
    
                // Find the url line.
                while (!line.contains("icon") && !line.contains("url")){
                    line = in.readLine();
                }
    
                // Find the path.
                QRegExp exp("\\((.*)\\)");
                if(exp.indexIn(line) < 0) {
                    row++;
                    continue;
                }
    
                // If its in the resource file, don't modify path.
                QString path = filepath;
                if (exp.cap(1).startsWith(":/")) {
                    path = exp.cap(1);
                } else {
                    path += exp.cap(1);
                }
    
                // Store the icons in the settings pane.
                OBSBasicSettings::setSettingsIcons(row, path);
                break;
            }
        }
    
        file.close();
    }
    

    In the desired class, hpp:

    static std::vector<QIcon> settingIcons;
    void setIcons();
    static void setSettingsIcons(int row, QString path) {
    	QIcon icon;
    	icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off);
    	settingIcons[row] = icon;
    }
    

    In the desired class cpp. I have 6 icons to change:

    std::vector<QIcon> OBSBasicSettings::settingIcons = []()->std::vector<QIcon> {
        std::vector<QIcon> v;
        v.reserve(6);
        for (int i = 0; i < 6; ++i) {
            v.push_back(QIcon());
        }
        return v;
    }();
    

    And the custom CSS:

    /* Settings Icons */
    /* This EXACT style and layout has to be used, since this section isn't part of Qt css. */
    /* Of course the url is arbitrary. Copy paste this and ONLY change the url. */
    /* Path is relative to .qss file. */
    
    #GeneralIcon {
        icon: url(./Dark/settings/general.png);
    }
    
    #StreamIcon {
        icon: url(./Dark/settings/stream.png);
    }
    
    #OutputIcon {
        icon: url(./Dark/settings/output.png);
    }
    
    #AudioIcon {
        icon: url(./Dark/settings/audio.png);
    }
    
    #VideoIcon {
        icon: url(./Dark/settings/video.png);
    }
    
    #AdvancedIcon {
        icon: url(./Dark/settings/advanced.png);
    }
    

    Now all you have to do is call setSettingsIcons when you read a qss theme file. Make sure to call setIcons() whenever you change the style of your app.

    Finally, Qt should support selectors and dynamic properties on QListWidgetItems, and I don't see why they don't inherit QObject anyways.


  • Lifetime Qt Champion

    For that kind of things the combo:
    QListView
    QStringListModel
    QIdentityProxyModel << Customize the icons here

    would do it in a simpler way.

    As for items being QObject derived classes, rather not. The various QXXXItem classes must be as lightweight as possible since there can be several thousands of them and QObject has a cost and constraints. Except maybe in a few corner cases there would be no real benefit to have it there for the common usage.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.