【问题标题】:Crash while calling setItemWidget调用 setItemWidget 时崩溃
【发布时间】:2016-02-11 03:25:29
【问题描述】:

我正在使用 QTreeWidget 并为 QTreeWidget 中的 QTreeWidgetItem 设置一个小部件。它工作正常,但是当我第二次这样做时,应用程序崩溃了。

下面的工作正常。

QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);

但是如果我再次添加最后一行,它会在运行应用程序时崩溃。

下面崩溃了。

QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0);       // Intentionally added to simulate the issue

以上是显示问题的示例,但在我的应用程序中,基于某些事件,我删除了树小部件项目并稍后添加。当我设置项目小部件(稍后添加项目后)时,我遇到了崩溃。

我不知道为什么。有任何想法吗?仅供参考,我使用的是 Qt 5.3.2 MSVC 2010,32 位。

【问题讨论】:

    标签: c++ qt qtreewidget qtreewidgetitem


    【解决方案1】:
    treewidget->setItemWidget(item0, 0, slider0);
    treewidget->setItemWidget(item0, 0, slider0);// Intentionally added to simulate the issue
    

    我看Qt代码(4.x):

    void QTreeWidget::setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget)
    {
        Q_D(QTreeWidget);
        QAbstractItemView::setIndexWidget(d->index(item, column), widget);
    }
    

    QAbstractItemView::setIndexWidget:

    void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
    {
        Q_D(QAbstractItemView);
        if (!d->isIndexValid(index))
            return;
        if (QWidget *oldWidget = indexWidget(index)) {
            d->persistent.remove(oldWidget);
            d->removeEditor(oldWidget);
            oldWidget->deleteLater();
        }
    

    所以如果你两次添加slider0,那么第一次调用它就被添加了, 在几秒钟内调用Qt调用它deleteLater,然后添加它, 确定这是你想要的吗?

    【讨论】:

      【解决方案2】:

      您必须在QTreeWidgetItem 的构造函数中设置正确的parent。试试这个:

      QTreeWidgetItem* item0 = new QTreeWidgetItem(treewidget);
      

      在调用setItemWidget() 之后了解谁是slider0 的所有者也很重要:所有者是你的表,所以1)你不需要删除这个对象; 2) 如果您再次为同一单元格调用setItemWidget,该对象将被删除。因此,treewidget->setItemWidget(item0, 0, slider0); 的双重调用似乎很奇怪(第二次将已删除的对象设置到该单元格中)。

      【讨论】:

      • @Sankar,好的,但是以任何方式设置正确的父级很重要。我已经扩展了我的答案(详见 user1034749 的答案)
      • @llya,实际上我正在尝试实现一个包含树小部件的属性窗口。每个树小部件项目都包含一个小部件(使用 setItemWidget() 设置)。属性窗口显示我正在选择的对象的属性。假设树小部件正在显示对象 A 的属性,我正在选择对象 B,当我再次选择对象 A 时,我正在删除树小部件中的项目(实际上属于对象 B)并添加对象 A 项目再次。当我这样做时,它没有我最初设置的项目小部件。所以我再次设置项目小部件,这导致了崩溃。
      • “实际上属于对象 B”是什么意思?如果它的意思是“实际上对应于”,那没关系(即,如果您在调用 setItemWidget 之前创建新的小部件)。但是,如果您使用该对象(对象 B 的一部分)上的指针作为 setItemWidget 的参数,这是错误的,因为在这种情况下您将失去所有权(这就是崩溃的原因)。
      • 不,我没有使用对象 B 的指针作为“setItemWidget”的参数。我两次使用相同的小部件作为“setItemWidget”的参数。正如你所说,当我第二次调用'setItemWidget'时它被删除了。这可能是坠机的一个原因。无论如何,我必须为我的用例寻找不同的方法。谢谢!
      猜你喜欢
      • 2015-02-23
      • 2019-02-22
      • 2018-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-20
      相关资源
      最近更新 更多