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

Posted

技术标签:

【中文标题】使用派生 Qt 小部件类时的父问题 (?)【英文标题】:Parent issue (?) while using derived Qt widget class 【发布时间】:2016-06-30 16:46:50 【问题描述】:

以下是我可以用来展示问题的最小示例。

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);

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

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

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:

;

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

【问题讨论】:

您正在添加一个空小部件,因此没有可显示的内容。如果您想证明是否存在某些东西,请尝试从QFrame 继承并在其上调用setFrameStyle(QFrame::Panel),以便获得小部件所在的边框 这是用 C++11 标记的,但它只是 C++98 :( Qt+C++11 看起来更好,更简洁! @KubaOber 请感谢我在***.com/questions/38130827/… 的 C++11 礼貌。 @KubaOber,除了您的反馈之外,是否有办法检查我离 C++11(甚至 14)还有多远?有什么工具吗? 【参考方案1】:

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

class MyGroupBox : public QWidget

您的“组框”基本上只是一个QWidget。而是从QGroupBox 继承。

【讨论】:

【参考方案2】:

顺便说一句,一个最小的示例可能如下所示。不能删除单个声明/语句/表达式。该按钮有助于可视化问题,因此应该保留它。失败触发器变量的使用准确地突出了触发失败的条件:代码自我记录,您几乎不需要叙述来解释它。问题可以像下面的测试用例一样简洁,一句话“为什么fail为真时,组框的边框不可见?”。最有可能的是,如果您完全遵循最小化,您就会意识到问题出在哪里——它变得相当明显。在另一个文件中声明MyGroupBox 时并非如此!

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

#include <QtWidgets>

struct MyGroupBox : public QWidget ;

int main(int argc, char ** argv) 
   bool fail = true;
   QApplication appargc, 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 的标头和实现可能如下所示:

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

class Widget : public QWidget 
  Q_OBJECT
  QVBoxLayout layoutthis;
  MyGroupBox groupBox;
  QPushButton buttontr("Click Me!");
public:
  explicit Widget(QWidget * parent = nullptr);
;

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

Widget::Widget(QWidget * parent) :
  QWidgetparent 
  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 layoutq_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) :
   QWidgetparent, d_ptrnew WidgetPrivatethis

【讨论】:

很高兴看到 Qt 程序员使用自动存储。 ;-) 这是否变得惯用了,指针无处不在的趋势只是那里大量过时示例代码的另一个例子,或者我搜索不佳......或者在这个意义上你仍然是少数?正如您之前评论的那样,过时的风格肯定存在问题,而具有现代 C++ 功能的 Qt 对我来说看起来更容易忍受。我只是想知道指针是否遵循类似的模式。堆栈语义是我如此喜欢 GTKmm 的一个主要原因(在它的接口中;当然,底层 C 都是动态的)。 我真的应该更喜欢 .h 中的 QVBoxLayout layoutthis 然后 .cpp 中的 QVBoxLayout *vLayout = new QVBoxLayout(this) 吗?您介意发布您的风格参考吗? 指针无处不在的趋势只是大量过时示例代码的另一个例子。更糟糕的是,即使在 Qt 4 中,甚至使用 C++98 编译器,也没有理由这样编码。通过指针保存 Qt 的容器和 QObjects 是双重间接的,因为 QObjectQVector 是指向 PIMPL 的指针……特别是 QObjectQScopedPointer&lt;QObjectPrivate&gt;。使用 C++11 编译时,Qt 4 和 Qt 5 源代码都可以简单地修改以使 QObject 和所有派生类型都可移动。 @KcFnMi Fwiw,我更喜欢 Kuba 语法的“参考”是我不使用指针,除非我有理由使用指针。可悲的是,Qt 示例代码似乎遵循相反的规则,我没有真正的理由能够解决。 @KcFnMi 对“我的”风格的“参考”是什么意思?按价值持有事物——这应该始终是默认的——除非你有很好的理由不这样做。那不是我的风格,那是基本的保守 C++ 编码。间接成本额外,额外的动态分配额外成本。随意使用它都是过早的悲观情绪。了解您编写的代码的语义。例如。成员声明的顺序是有意义的,不能是任意的。我遇到了一个 C++ 代码库,他们坚持按字母顺序对所有类成员声明进行排序......坚果。

以上是关于使用派生 Qt 小部件类时的父问题 (?)的主要内容,如果未能解决你的问题,请参考以下文章

Qt 设计师;难以将小部件放置在正确的父级中

具有单独布局的嵌套 Qt 小部件

透明小部件不随其父级移动

具有完全透明背景的 qt 小部件

Qt半透明背景导致子小部件在父小部件中“印记”

如何在 Qt 中将消息从子窗口小部件发送到父窗口?