4

当您以编程方式添加 QWidget 时,初始化 QWidget 的最佳方式(位置)是什么?

我可以想办法做到这一点:

1) 在定义文件中创建实例,然后在初始化器列表中对其进行初始化。这似乎是正确的方法,但是您需要添加到窗口中的 QWidget 越多,它就会变得有点草率。

class SomeWindow : QDialog{
...
private:
  QLabel label1;
  QLabel label2;
...
}

SomeWindow::SomeWindow(...) : QDialog(...),
 label('label1 text'), label('label2 text')
{
...
  layout.addWidget(&label1);
  layout.addWidget(&label2);
...
}

2)来自C#我倾向于喜欢这个,但它似乎会产生内存泄漏......

SomeWindow::SomeWindow(...) : QDialog(...)
{
  QLabel* label1 = new QLabel('label1 text');
  QLabel* label2 = new QLabel('label2 text');
...
  layout.addWidget(label1);
  layout.addWidget(label2);
...
}

有没有更好的方法来做到这一点,我错过了?

我为新手的问题道歉。

4

3 回答 3

3

Qt使用自己的系统来删除QObject派生类的父子类。当您删除对象时,所有子对象也将被删除。

使用第一个代码,您有 2 个破坏(在 SomeWindow 的析构函数和 QObject 系统中),那么这段代码是非法的(仅使用 Qt ;使用 C++ 标准代码,很好)

使用第二个代码,标签被 QObject 系统删除,你没有内存泄漏。无需在对象上保留指针。

@Jairo

在构造函数中设置父级并不是将子级添加到对象的唯一方法。特别是,在这里, QLayout::addWidget 重新父对象(如果布局正确地是对象的子对象)

@msgmaxim

注意,布局不能是构造函数中的局部变量

于 2013-09-25T06:58:18.963 回答
1

在标题中包含指向小部件的指针而不是实际对象的一个​​优点是您不需要包含小部件的所有标题,而只需向前声明它们。这增加了编译时间,这在大型项目中可能相当明显。

此外,如果您有一个对话框并且只是添加了很多小部件,例如 QLabel,您可以通过在实现中执行以下操作来使代码更整洁:-

layout.addWidget(new QLabel('label1 text'));
layout.addWidget(new QLabel('label2 text'));
layout.addWidget(new QLabel('label3 text'));
layout.addWidget(new QLabel('label4 text'));

如前所述,Qt 的父系统会在其父系统被删除时负责清理这些小部件。

当然,如果你想改变一个属性,比如文本,那么你需要从布局的子元素中找到小部件,但通常 QLabel,顾名思义,只是标记一个项目而它的属性不是改变了。

于 2013-09-25T07:57:44.303 回答
1

有两种方法可以很好地初始化一个新的小部件。

第一种情况,您将标签作为对象。所以当 SomeWindow 被销毁时,它们也会被自动销毁。请记住,如果您有指向小部件而不是对象的指针,您将需要(并且可以)将标签删除到对话框的析构函数中。

SomeWindow::~SomeWindow()
{
    delete label1;
    label2.deleteLater(); // A safer way to delete a widget. Thread-safe.
}

第二种情况会出现内存泄漏,因为您无法将小部件删除到析构函数中。但是如果你为标签定义了一个父级,当父级也被删除时,它们也会被删除。查看QWidget 文档

如果 parent 为 0,则新的小部件将成为一个窗口。如果 parent 是另一个小部件,则此小部件将成为 parent 内的子窗口。新小部件在其父小部件被删除时被删除。

此外,任何时候对象构造函数要求您提供父 QWidget 或 QObject,您可以认为 Qt 会在删除父对象时删除该对象。

我也是新手,希望对你有帮助。

于 2013-09-25T06:39:32.787 回答