#c #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 intamp; 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 amp;amp; currentUnit->getAction()->getTimeStart() == currentUnit->getAction()->getTimeCurrent()
amp;amp; (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 amp;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
, как и та, в которой он находится).
Комментарии:
1. Не могли бы вы показать соответствующую таблицу стилей ?
2. таблица стилей = фон: rgb(170, 0, 255);граница: 2 пикселя сплошной черный;
3. После нескольких часов поиска в Интернете я узнал об этом developer.qt.nokia.com/forums/viewthread/7340 Код, указанный на этой странице, был необходим для работы таблицы стилей.
4. @jecjackal: Если вы нашли решение, пожалуйста, отправьте его в качестве ответа на этот вопрос в интересах любых будущих зрителей.
Ответ №1:
У меня была аналогичная проблема, и она была решена с помощью комментария Джекджекала. Как сказал Шварнер, это было бы гораздо более заметно в форме ответа. Так что я его предоставлю. На благо любых будущих зрителей. Опять же, это не мой ответ! Ценю джекджекала за это!
Как сказано в справочнике таблиц стилей Qt, применение стилей CSS к пользовательским виджетам, унаследованным от QWidget, требует переопределения paintEvent() таким образом:
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, amp;opt, amp;p, this);
}
Без этого ваши пользовательские виджеты будут поддерживать только свойства фона, клипа фона и источника фона.
Вы можете прочитать об этом здесь: Ссылка на таблицы стилей Qt в разделе «Список стилизуемых виджетов» -> QWidget.
Ответ №2:
Есть ответ гораздо проще, чем написать свой собственный paintEvent
: подкласс QFrame
вместо QWidget
и он будет работать сразу:
class WidgetUnits : public QFrame
{
Q_OBJECT
....
Комментарии:
1. Я обнаружил, что это гораздо менее навязчивый способ решения проблемы. Достаточно просто найти/заменить эту строку для каждого пользовательского виджета, а также выполнить это в части счетчика файлов cpp, заменив QWidget(родительский) на QFrame(родительский) в конструкторе по умолчанию.
Ответ №3:
Для полноты картины та же проблема присутствует и в 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)
Комментарии:
1. Какой импорт мне для этого нужен? Я получаю
AttributeError: module 'PyQt5.QtGui' has no attribute 'QStyleOption'
, если импортирую QtGui, а из QtWidgets импортирую QStyleOption.
Ответ №4:
У меня была такая же проблема с пайсидом. Я публикую свое решение просто для полноты картины. Это почти как в 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{...}
Ответ №5:
Вызов setAttribute(Qt::WA_StyledBackground, true)
пользовательского виджета сработал для меня.
Ответ №6:
Установка Qt::WA_StyledBackground в значение true работает только в том случае, если вы не забыли добавить Q_OBJECT в свой класс. С этими двумя изменениями вам не нужно повторно использовать paintEvent.