Qt Q_OBJECT宏导致样式表出现意外行为

时间:2019-07-10 17:33:24

标签: c++ qt

我写了一个自定义的Qt小部件,扩展了QWidget类。

让我们考虑以下代码:

.h

#ifndef SS_TEST_H
#define SS_TEST_H

#include <QMainWindow>

class TestWidget : public QWidget
{
    Q_OBJECT // ***>>> BUG HERE <<<***

    public:
        TestWidget(const QString & v1, const QString & v2, QWidget * parent = nullptr);
};

class TestWindow : public QMainWindow
{
    Q_OBJECT

    public:
        TestWindow();
};

#endif // SS_TEST_H

.cpp

#include "ss_test.h"

#include <QGridLayout>
#include <QLabel>
#include <QApplication>

TestWidget::TestWidget(const QString & v1, const QString & v2, QWidget * parent) : QWidget(parent)
{
    QGridLayout * lay = new QGridLayout;

    QLabel * field = new QLabel(v1, this);
    QLabel * value = new QLabel(v2, this);
    value->setMinimumWidth(80);
    value->setAlignment(Qt::AlignCenter);
    value->setStyleSheet("QLabel { background-color: white; border: 1px solid silver; }");

    lay->addWidget(field, 0, 0);
    lay->addWidget(value, 0, 1);

    this->setLayout(lay);

    this->setStyleSheet("QWidget { background-color: red; }");
}

TestWindow::TestWindow()
{
    setWindowTitle("ss test");
    resize(400, 300);

    QWidget * cw = new QWidget;
    QVBoxLayout * cl = new QVBoxLayout;

    TestWidget * tw1 = new TestWidget("Field 1", "Value 1", this);
    TestWidget * tw2 = new TestWidget("Field 2", "Value 2", this);

    cl->addWidget(tw1);
    cl->addWidget(tw2);
    cl->addStretch();

    cw->setLayout(cl);
    this->setCentralWidget(cw);
}

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    TestWindow tw;
    tw.show();

    return app.exec();
}

我正在谈论的小部件是TestWidget类。

在类声明中没有Q_OBJECT宏,我得到的正是我想要的样式: enter image description here

但是,如果我在类声明的开头添加了Q_OBJECT宏(如您在头文件中看到的注释),它会意外地修改小部件的样式: enter image description here

我不明白这里会发生什么。

当然,在我的真实项目中,此小部件比在此最小示例中要复杂得多,并且必然需要Q_OBJECT宏(以便使用信号/插槽机制和qobject_cast

如果有人能向我解释Q_OBJECT在这里的工作以及原因,我将不胜感激。

1 个答案:

答案 0 :(得分:2)

必须仔细阅读文档才能偶然发现正确的passage

您的TestWidget类需要重新实现paintEvent:

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

还有一个重要说明,您必须定义Q_OBJECT宏。

  

警告:请确保为自定义窗口小部件定义了Q_OBJECT宏。

我尝试过,这种行为似乎符合您的需求。

在缺少Q_OBJECT的情况下,这种奇怪行为的可能解释可能是qobject_cast<TestWidget*>(widget)将产生nullptr。这可能会导致呈现的样式表出现不同的行为。