自定义小部件的 Qt 样式表
Posted
技术标签:
【中文标题】自定义小部件的 Qt 样式表【英文标题】:Qt Stylesheet for custom widget 【发布时间】:2011-11-08 17:34:51 【问题描述】:我当前的项目中有几个自定义小部件。我希望对它们应用样式表,当我在 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
的颜色相同)。
【问题讨论】:
你能显示相应的样式表吗? 样式表 = 背景:rgb(170, 0, 255);\n边框:2px 纯黑色; 在网上搜索了几个小时后,我发现了这个developer.qt.nokia.com/forums/viewthread/7340 该页面上引用的代码是样式表工作所必需的。 @jecjackal:如果您找到了解决方案,请将其作为此问题的答案提交,以供未来的观众使用。 【参考方案1】:我遇到了类似的问题,使用 jecjackal 的评论解决了。正如 sjwarner 所说,以答案的形式会更加引人注目。所以我会提供。为了任何未来的观众的利益。再说一遍,这不是我的答案!感谢它!
正如 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 Stylesheets reference 在“可样式化小部件列表”部分 -> QWidget。
【讨论】:
【参考方案2】:为了完整起见,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)
【讨论】:
我需要哪些进口?如果我导入 QtGui 并从 QtWidgets 导入 QStyleOption,我会得到AttributeError: module 'PyQt5.QtGui' has no attribute 'QStyleOption'
。【参考方案3】:
有一个答案比编写自己的paintEvent
容易得多:子类QFrame
而不是QWidget
,它会立即起作用:
class WidgetUnits : public QFrame
Q_OBJECT
....
【讨论】:
我发现这是解决问题的一种不那么侵入性的方式。它很容易找到/替换每个自定义小部件的那一行,以及通过在默认构造函数中将 QWidget(parent) 替换为 QFrame(parent) 来对 cpp 文件对应部分执行此操作。【参考方案4】:我对 pyside 也有同样的问题。我发布我的解决方案只是为了完整性。 就像 Pieter-Jan Busschaert 提出的那样,它几乎就像在 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。
【讨论】:
以上是关于自定义小部件的 Qt 样式表的主要内容,如果未能解决你的问题,请参考以下文章