C++ 调用setItemWidget时崩溃

C++ 调用setItemWidget时崩溃,c++,qt,qtreewidget,qtreewidgetitem,C++,Qt,Qtreewidget,Qtreewidgetitem,我正在使用QTreeWidget并在QTreeWidget中为QTreeWidgetItem设置一个小部件。它工作正常,但当我第二次这样做时,应用程序崩溃了 QTreeWidget* treewidget = new QTreeWidget(); QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0"))); treewidget->insertTopLevelIte

我正在使用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);
treewidget->setItemWidget(item0, 0, slider0);       // Intentionally added to simulate the issue
下面的工作正常

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位。

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

QTreeWidgetItem* item0 = new QTreeWidgetItem(treewidget);
调用
setItemWidget()
后,了解谁是
slider0
的所有者也很重要:所有者是您的表,因此1)您不需要删除此对象;2) 如果再次为同一单元格调用
setItemWidget
,该对象将被删除。因此,双重调用
treewidget->setItemWidget(item0,0,slider0)看起来很奇怪(第二次将删除的对象设置到该单元格中时)

我看一下Qt代码(4.x):

qabstractemview::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
,然后添加它,
你确定这就是你想要的吗?

@Sankar,好的,但无论如何设置正确的父项都很重要。我已经扩展了我的答案(请参阅user1034749答案中的详细信息)@llya,实际上我正在尝试实现一个包含树小部件的属性窗口。每个树小部件项都包含一个小部件(使用setItemWidget()设置)。属性窗口显示我正在选择的对象的属性。假设树小部件显示对象A的属性,我选择对象B,当我再次选择对象A时,我删除树小部件中的项目(实际上属于对象B)并再次添加对象A项目。当我这样做时,它没有我最初设置的项目小部件。所以我再次设置了item小部件,这导致了崩溃。“实际上属于对象B”是什么意思?如果它的意思是“实际对应于”,则可以(即,如果您在调用
setItemWidget
之前创建了新的小部件)。但是,如果您使用对象(对象B的一部分)上的指针作为
setItemWidget
的参数,这是错误的,因为在这种情况下,您将失去所有权(这就是崩溃的原因)。不,我没有使用对象B的指针作为“setItemWidget”的参数。我两次使用同一个小部件作为“setItemWidget”的参数。正如您所说,当我第二次调用“setItemWidget”时,它被删除。这可能是坠机的原因之一。无论如何,我必须为我的用例寻找不同的方法。谢谢
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();
    }