【问题标题】:Qt: Setup my own QWidget in the right wayQt:以正确的方式设置我自己的 QWidget
【发布时间】:2010-03-29 13:15:03
【问题描述】:

在 Qt 中,我正在尝试设置自己的 QWidget,因此由于内存管理和其他事情,一切都应该正常工作。但我似乎无法用指针、堆和堆栈来解决问题。我有我的小部件 MyWidget,它有一个带有一些对象的 QList。我不知道如何正确设置所有内容。

您可以在下面看到我的代码,我对此有一些疑问:

  1. instace变量列表是在堆上创建的,是不是在栈上创建比较好?

  2. 在我的列表中我有指针,在堆栈上创建对象并将其附加到列表中会更好吗? (所以我在列表中根本没有指针)

  3. 当我将对象附加到列表时,它们会自动将列表作为其父对象吗?那么当我删除列表时,列表中的所有对象都会被删除?

  4. 我尝试使用的 for each 循环不起作用,我得到“此操作需要指针/数组类型而不是 'int'”

  5. 在我的代码中,我想创建其他小部件,将列表中的对象作为参数。这是像我一样做的正确方法吗? MyOtherWidget 的实例方法如下所示:MyOtherWidget(MyObject *myObject, QWidget *parent)

感谢您的帮助!我是 Qt 和 C++ 的新手,所以如果你能引导我朝着正确的方向前进,那就太好了。我怎样才能以正确的方式设置它以使其变得容易,不要出现内存泄漏并根据需要使用尽可能少的内存。你会如何设置同样的东西?

这是我的代码:

MyWidget.h:

class MyWidget : public QWidget
{
Q_OBJECT

public:
    MyWidget(QWidget *parent = 0);
    ~MyWidget();

private:
    QList<MyObject*> *list;
};

MyWidget.cpp:

MyWidget::MyWidget(QWidget *parent)
{
    ui.setupUi(this);

    list = new QList<MyObject*>();
    for (int i = 0; i<10; i++) 
    {
        MyObject *myObject = new MyObject("Hello",this);
        list->append(myObject);
    }

    foreach(MyObject *myObject, list)
    {
        //Lets say I want to create other widgets here and that they takes a MyObject as a parameter
        MyOtherWidget *myOtherWidget = new MyOtherWidget(myObject,this);
    }

}

MyWidget::~MyWidget(){
    delete list;
}

【问题讨论】:

    标签: qt memory-management qobject


    【解决方案1】:

    广告 1。列表的生命周期应该与 MyWidget 实例的生命周期相同,因此您可以安全地在堆栈上创建列表。

    广告 2。你可以这样做,但 MyObject 类需要有一个默认构造函数、一个复制构造函数和一个赋值运算符(有关详细信息,请参阅http://doc.trolltech.com/4.6/containers.html#container-classes)。

    广告 3。对象的所有权不会在追加时转移。就像 STL 容器一样,Qt 容器不会对存储的指针调用 delete。要删除存储在 QList(或其他 Qt 容器)中的所有指针,您可以使用 qDeleteAll(list)。请注意,您可能不想在您发布的代码中这样做:您将 MyWidget 指针传递给 MyObject 构造函数,然后我假设它用作 QObject 父级。所以当 MyWidget 被删除时,所有的 QObjects 都会被删除。

    广告 4。 foreach 宏的第二个参数应该是一个容器,而不是指向容器的指针。因此,如果您的列表变量是指向 QList 的指针,您应该调用 foreach(MyObject *obj, *list)。

    广告 5。只要 MyOtherWidget 不删除传递的 MyObject 就可以了(因为 MyWidget 已经是 MyObject 的父对象,您最终会删除同一个对象两次)。

    这是一个非常简单的方法,但您应该尝试以完全不需要调用 delete 的方式编写代码。在堆栈上创建东西或依赖 Qt 父子机制(即父母删除他们的孩子)。稍后您可能想了解智能指针(QSharedPointer、QScopedPointer 等)。

    编辑:

    是否设置了 MyObject 的父级取决于您在 MyObject 构造函数中所做的事情。如果您将父参数传递给 QObject 构造函数,即您的 Myobject 构造函数如下所示:

    MyObject(const QString &text, QObject *parent = 0) : QObject(parent)
    {
    // more code...
    }
    

    parent 将被设置,因为它将在 QObject 构造函数中完成,因为 ":QObject(parent)" 代码将调用该构造函数。如果你没有这个片段怎么办?由于 MyObject 继承了 QObject,并且您没有指定应调用默认 QObject 构造函数的构造函数,即将调用 QObject(QObject *parent = 0),因此 MyObject 的父级将为 NULL 而不会已删除。

    我会尽量避免通过 setParent 方法显式设置父级 - 对于基本用例,在构造函数中设置父级就足够了。

    尝试使用正确的术语(不是“实例方法”,而是“构造函数”),阅读 Qt 文档,使用常识,尽量不要认为任何事情都会自动完成。父级不会因为您调用一个参数“父级”而“自动”设置 - 它已设置,因为在 QObject 构造函数中有一段代码可以执行此操作,并且您有责任在类中调用将正确的父级传递给 QObject 构造函数继承 QObject。

    【讨论】:

    • 谢谢!还有一个问题,MyObject 的实例方法看起来像 MyObject(QString *string, QObject *parent = 0)。当我使用 new MyObject("Hello",this);我需要在 MyObject 的实例方法中有 this->setParent(parent) 吗?或者父母会自动设置吗?如果我在实例方法中使用 setParent() 如果我将父级留空会发生什么?抱歉所有问题,但您的回答对您有很大帮助!
    【解决方案2】:

    是的,问题是您要删除列表的对象而不是其元素!

    我建议你看看:

    QList<Employee *> list;
    list.append(new Employee("Blackpool", "Stephen"));
    list.append(new Employee("Twist", "Oliver"));
    
    qDeleteAll(list.begin(), list.end());
    list.clear();
    

    More info here

    我还要问你是否真的需要一个指向你的列表的指针?你可以有一个简单的:

    QList<MyObject*> list;
    

    因此,内存泄漏的可能性降低了!

    希望这会有所帮助!

    编辑:
    3. 您的 MyObject 对象将“this”作为父对象。处理指针时,该列表不获取对象所有权。
    4. 对于循环,也许你应该考虑迭代器,看看这里qthelp://com.trolltech.qt.460/qdoc/qlist.html

    【讨论】:

    • 如果我不使用指向列表的指针而只使用 QList 列表。这个对象什么时候会被删除?非常感谢您的帮助!
    • 好吧,这取决于...如果列表元素以 MyWidget 作为父级,那么,当它们的父级被删除时,它们将被删除...如果它们没有任何父级,您将拥有在 MyWidget 的析构函数中删除它们...请记住,当您处理指针时,都是关于“谁拥有这个指针?”...所有者处理其指针的删除...
    • 但是如果我不按照您上面的建议使用列表指针。什么时候删除列表?我理解的列表中的对象将根据其父对象被删除。但是列表呢?
    • 好吧,既然列表是 MyWidget 类的一个实例的成员...当对象被删除时它将被删除...但是同样,列表对象将被删除,而不是它的内容(如果它包含指针)!
    • 好吧,我明白了。关于同一件事的另一个问题:如果我使用 QGraphicsScene::addItem(item) 是否会将项目的父项设置为 QGraphicsScene ,以便在删除场景时项目也会被删除?我对 QLayout::addItem ( item ) 也有同样的问题?这是 Qt 文档中的任何地方吗?
    【解决方案3】:

    您不需要将子窗口小部件存储在列表中,只要您将它们设为当前窗口小部件的父窗口即可。 (通常您使用 new 在堆栈上创建小部件)。

    Qt 有一个自动清理功能,这意味着,如果一个小部件被删除,所有子小部件(其父小部件是被删除的小部件的小部件)都会被删除。

    因此,您唯一需要确保(尤其是对于临时弹出窗口小部件)擦除/删除窗口小部件“弹出窗口”或您调用弹出窗口小部件的方式。

    就是这样,就是这样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-24
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      • 2020-03-09
      • 1970-01-01
      相关资源
      最近更新 更多