Таблица стилей Qt для пользовательского виджета

В моем текущем проекте есть несколько настраиваемых виджетов. Я хочу применить к ним таблицы стилей, и когда я делаю это внутри Qt Creator, кажется, что это работает. Однако при выполнении программы таблица стилей не используется. Таблицы стилей для виджетов Qt работают нормально.

Есть ли у кого-нибудь совет? вот некоторый соответствующий код.

WidgetUnits.h

#ifndef WIDGETUNITS_H
#define WIDGETUNITS_H

#include <QList>

#include <QWidget>
#include <QPainter>

#include <Widgets/JECButton.h>

#include <Unit.h>
#include <Time.h>

namespace Ui
{
    class WidgetUnits;
}

class WidgetUnits : public QWidget
{
    Q_OBJECT

public:
    explicit WidgetUnits(QWidget *parent = 0);
    ~WidgetUnits();

    void setNumTimes(const int& numTimes);

public slots:
    void updatePictures(const Time* time);

protected:
    void paintEvent(QPaintEvent *event);
private:
    void checkNewQueue(const QList<QList<Unit*>*>* units);
    Ui::WidgetUnits *ui;

    const int pictureWidth;                         // The width of the Unit pictures.
    const int pictureHeight;                        // The height of the Unit pictures.

    QList<QList<JECButton*>*> buttonPictures;       // The Units' pictures. The outer QList stores the QList of pictures for a given tick.
                                                    // The inner QList stores the JECButtons for the specific tick.
};

WidgetUnits.cpp

#include "WidgetUnits.h"
#include "ui_WidgetUnits.h"

WidgetUnits::WidgetUnits(QWidget *parent):
    QWidget(parent),
    ui(new Ui::WidgetUnits),
    pictureWidth(36),
    pictureHeight(36)
{
    ui->setupUi(this);
}

WidgetUnits::~WidgetUnits()
{
    delete ui;
}

void WidgetUnits::updatePictures(const Time *time)
{
    // Only showing units that started to get built this turn.
    checkNewQueue(time->getUnits());
    checkNewQueue(time->getBuildings());
    checkNewQueue(time->getUpgrades());

    // Updating the position of the remaining pictures (after some were removed).
    // Checking the maximum number of Units made in one tick.
    int maxNewQueue = 0;
    for (int a = 0; a < buttonPictures.length(); ++a)
    {
        if (buttonPictures.at(a)->length() > maxNewQueue)
        {
            maxNewQueue = buttonPictures.at(a)->length();
        }
    }

    if (buttonPictures.length() > 0)
    {
        this->setGeometry(0, 0, buttonPictures.length() * 130,
                          maxNewQueue * (pictureWidth + 10) + 20);

        QList<JECButton*>* tickButtons = 0;
        for (int a = 0; a < buttonPictures.length(); ++a)
        {
            tickButtons = buttonPictures.at(a);
            for (int b = 0; b < tickButtons->length(); ++b)
            {
                tickButtons->at(b)->move(a * 130, b * (pictureHeight + 10));
            }
        }
    }
    update();
}

void WidgetUnits::checkNewQueue(const QList<QList<Unit *> *> *units)
{
    if (units != 0)
    {
        const Unit* currentUnit = 0;
        JECButton* currentButton = 0;
        for (int a = 0; a < units->length(); ++a)
        {
            buttonPictures.append(new QList<JECButton*>());

            for (int b = 0; b < units->at(a)->length(); ++b)
            {
                currentUnit = units->at(a)->at(b);

                // Verifying that there is an item in the queue and the queue action was started this turn.
                if (currentUnit->getQueue() != 0 && currentUnit->getAction()->getTimeStart() == currentUnit->getAction()->getTimeCurrent()
                        && (currentUnit->getAction()->getType() == Action::BUILD || currentUnit->getAction()->getType() == Action::TRAIN ||
                            currentUnit->getAction()->getType() == Action::UPGRADE))
                {
                    buttonPictures.last()->append(new JECButton(this));
                    currentButton = buttonPictures.last()->last();

                    QImage* image = new QImage(currentUnit->getQueue()->getUnitBase()->getImage().scaled(pictureWidth, pictureHeight));
                    currentButton->setImage(*image);
                    currentButton->setGeometry(0, 0, currentButton->getImage().width(),
                                                       currentButton->getImage().height());
                    currentButton->setColorHover(QColor(0, 0, 225));
                    currentButton->setColorPressed(QColor(120, 120, 120));
                    currentButton->setImageOwner(true);
                    currentButton->setVisible(true);
                }
            }
        }
    }
}

void WidgetUnits::setNumTimes(const int &numTimes)
{
    // Appending new button lists for added ticks.
    for (int a = buttonPictures.length(); a < numTimes; ++a)
    {
        buttonPictures.append(new QList<JECButton*>());
    }
}

void WidgetUnits::paintEvent(QPaintEvent *event)
{
    QWidget::paintEvent(event);
}

Любая помощь будет оценена по достоинству.

Виджет виден - я установил всплывающую подсказку, которую он мне показал (он того же цвета, что и QScrollArea, в котором он сидит).

Jec


person jecjackal    schedule 01.09.2011    source источник
comment
Не могли бы вы показать соответствующую таблицу стилей?   -  person alexisdm    schedule 02.09.2011
comment
таблица стилей = background: rgb (170, 0, 255); \ nborder: 2px сплошной черный;   -  person jecjackal    schedule 02.09.2011
comment
После нескольких часов поиска в Интернете я узнал об этом developer.qt.nokia.com / форумы / viewthread / 7340 Код, указанный на этой странице, был необходим для работы таблицы стилей.   -  person jecjackal    schedule 02.09.2011
comment
@jecjackal: Если вы нашли решение, отправьте его в качестве ответа на этот вопрос в интересах всех будущих зрителей.   -  person sam-w    schedule 12.11.2011


Ответы (6)


У меня была аналогичная проблема, и она была решена с помощью комментария jecjackal. Как сказал sjwarner, это было бы гораздо заметнее в форме ответа. Я предоставлю это. На благо всех будущих зрителей. Опять же, это не мой ответ! Спасибо за это Jecjackal!

Как сказано в справочнике по таблицам стилей Qt, применение стилей CSS к пользовательским виджетам, унаследованным от QWidget, требует повторной реализации paintEvent () таким образом:

 void CustomWidget::paintEvent(QPaintEvent *)
 {
     QStyleOption opt;
     opt.init(this);
     QPainter p(this);
     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
 }

Без этого ваши пользовательские виджеты будут поддерживать только свойства background, background-clip и background-origin.

Вы можете прочитать об этом здесь: Справочник по таблицам стилей Qt в разделе «Список стилизованных виджетов» -> QWidget.

person Roman Kruglov    schedule 11.01.2012

Есть ответ намного проще, чем писать свой собственный paintEvent: subclass QFrame вместо QWidget, и он сразу заработает:

class WidgetUnits : public QFrame
{
    Q_OBJECT
....
person Marco    schedule 28.02.2014
comment
Я обнаружил, что это гораздо менее навязчивый способ решения проблемы. Достаточно просто найти / заменить эту одну строку для каждого настраиваемого виджета, а также сделать это для счетчика файла cpp, заменив QWidget (родительский) на QFrame (родительский) в конструкторе по умолчанию. - person Yattabyte; 12.04.2015

Для полноты, та же проблема присутствует в PyQt. Вы можете применить таблицу стилей к подклассу QWidget, добавив аналогичный код:

def paintEvent(self, pe):
  opt = QtGui.QStyleOption()
  opt.init(self)
  p = QtGui.QPainter(self)
  s = self.style()
  s.drawPrimitive(QtGui.QStyle.PE_Widget, opt, p, self)
person Pieter-Jan Busschaert    schedule 10.07.2013
comment
Какой импорт мне нужен для этого? Я получаю AttributeError: module 'PyQt5.QtGui' has no attribute 'QStyleOption', если импортирую QtGui, а из QtWidgets импортирую QStyleOption. - person ewi; 12.05.2021

У меня была такая же проблема с писайдом. Я выкладываю свое решение только для полноты картины. Это почти как в PyQt, как предложил Питер-Ян Бушарт. Единственная разница в том, что вам нужно вызвать initFrom вместо init

def paintEvent(self, evt):
    super(FreeDockWidget,self).paintEvent(evt)
    opt = QtGui.QStyleOption()
    opt.initFrom(self)
    p = QtGui.QPainter(self)
    s = self.style()
    s.drawPrimitive(QtGui.QStyle.PE_Widget, opt, p, self) 

Еще одна вещь, которую вам нужно убедиться, это то, что вы определяете свой настраиваемый виджет в своем файле css следующим образом:

FreeDockWidget{...}

и не нравится часто рекомендуется

QDockWidget#FreeDockWidget{...}
person Stefan Reinhardt    schedule 29.04.2014
comment
Сегодня ты мой герой. - person Nisba; 11.02.2020

Вызов setAttribute(Qt::WA_StyledBackground, true) для настраиваемого виджета у меня сработал.

person mentalmushroom    schedule 08.03.2018

Установка Qt :: WA_StyledBackground на true работает, только если вы не забыли добавить Q_OBJECT в свой класс. С этими двумя изменениями вам не нужно повторно реализовывать paintEvent.

person Dejan Stankovic    schedule 24.09.2019