使用派生 Qt 小部件时的父问题 (?) class

Parent issue (?) while using derived Qt widget class

下面是我能做的最小的例子来展示问题。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QVBoxLayout *vLayout = new QVBoxLayout(this);

    QGroupBox *gb = new QGroupBox;
//    MyGroupBox *gb = new MyGroupBox;
    vLayout->addWidget(gb);

    QPushButton *btB = new QPushButton;
    vLayout->addWidget(btB);
}

上面的代码产生了上图,它只是一个组合框和一个垂直布局的按钮。

如果我用 MyGroupBox 替换 QGropBox 那么它就不会再显示了。下面的代码生成下面的图像。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QVBoxLayout *vLayout = new QVBoxLayout(this);

//    QGroupBox *gb = new QGroupBox;
    MyGroupBox *gb = new MyGroupBox;
    vLayout->addWidget(gb);

    QPushButton *btB = new QPushButton;
    vLayout->addWidget(btB);
}

其中mygroupbox.h(.cpp文件中构造函数体为空):

#include <QWidget>

class MyGroupBox : public QWidget
{
    Q_OBJECT
public:
    explicit MyGroupBox(QWidget *parent = 0);

signals:

public slots:

};

为什么组框没有显示在那里?如何让它出现?

这就是它没有出现的原因:

class MyGroupBox : public QWidget

你的 "group box" 基本上只是一个 QWidget。而是从 QGroupBox 继承。

顺便说一句,一个最小的例子可能如下所示。没有一个 declaration/statement/expression 可以删除。该按钮有助于可视化问题,因此应该保留它。失败触发变量的使用突出显示了触发失败的确切条件:代码 self-documents,您几乎不需要叙述来解释它。问题可以像下面的测试用例和一句话"Why is the group box's border not visible when fail is true?"一样简洁。最有可能的是,如果您完全遵循最小化,您自己就会意识到问题所在 - 它变得相当明显。在另一个文件中声明 MyGroupBox 时就不是这样了!

将所有内容放入单个 main.cpp 文件的技术对于发现问题 至关重要 :所有代码在物理上彼此相邻,因此更容易发现错误!当您最小化时,通常首先要做的是单独的文件:将它们全部塞进一个文件,然后毫不留情地完全删除重现问题时不需要的所有内容。

#include <QtWidgets>

struct MyGroupBox : public QWidget {};

int main(int argc, char ** argv) {
   bool fail = true;
   QApplication app{argc, argv};
   QWidget widget;
   QVBoxLayout layout{&widget};
   QGroupBox groupBox;
   MyGroupBox myGroupBox;
   QPushButton button;
   layout.addWidget(fail ? static_cast<QWidget*>(&myGroupBox) : &groupBox);
   layout.addWidget(&button);
   widget.show();
   return app.exec();
}

这种简洁的风格不仅适用于琐碎的测试用例。在您的实际代码中,Widget 的 header 和实现可能如下所示:

// Widget.h
#include <QtWidgets>
#include "MyGroupBox.h"

class Widget : public QWidget {
  Q_OBJECT
  QVBoxLayout layout{this};
  MyGroupBox groupBox;
  QPushButton button{tr("Click Me!")};
public:
  explicit Widget(QWidget * parent = nullptr);
};

// Widget.cpp
#include "Widget.h"

Widget::Widget(QWidget * parent) :
  QWidget{parent} {
  layout.addWidget(&groupBox);
  layout.addWidget(&button);
}

如果您坚持要从实现细节中屏蔽接口,请不要使用指向小部件等的指针,请使用 PIMPL

// Widget.h
#include <QWidget>

class WidgetPrivate;
class Widget : public QWidget {
   Q_OBJECT
   Q_DECLARE_PRIVATE(Widget)
   QScopedPointer<WidgetPrivate> const d_ptr;
public:
   explicit Widget(QWidget * parent = nullptr);
};

// Widget.cpp
#include "Widget.h" // should always come first!
#include "MyGroupBox.h"

class WidgetPrivate {
   Q_DECLARE_PUBLIC(Widget)
   Widget * const q_ptr;
public:
   QVBoxLayout layout{q_func()};
   QGroupBox groupBox;
   MyGroupBox myGroupBox;
   QPushButton button{"Click Me!"};
   WidgetPrivate(Widget * q) : q_ptr(q) {
      layout.addWidget(&groupBox);
      layout.addWidget(&button);
   }
};

Widget::Widget(QWidget * parent) :
   QWidget{parent}, d_ptr{new WidgetPrivate{this}}
{}