Сбой при вызове setItemWidget

Я использую QTreeWidget и устанавливаю виджет для QTreeWidgetItem в QTreeWidget. Он работает нормально, но когда я делаю то же самое во второй раз, приложение вылетает.

Ниже работает нормально.

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-разрядную версию.


person Sankar    schedule 10.11.2015    source источник


Ответы (2)


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

так что если вы добавите слайдер0 два раза, то при первом вызове он добавился, при секундном вызове Qt вызовите для него deleteLater, а затем добавили его, уверены, что это то, что вы хотите?

person fghj    schedule 10.11.2015

Вы должны установить правильный parent в конструкторе QTreeWidgetItem. Попробуй это:

QTreeWidgetItem* item0 = new QTreeWidgetItem(treewidget);

Также важно понимать, кто является владельцем slider0 после вызова setItemWidget(): владельцем является ваша таблица, поэтому 1) вам не нужно удалять этот объект; 2) объект будет удален, если вы снова вызовете setItemWidget для той же ячейки. Итак, двойной вызов treewidget->setItemWidget(item0, 0, slider0); кажется очень странным (второй раз вы устанавливаете удаленный объект в эту ячейку).

person Ilya    schedule 10.11.2015
comment
@Sankar, хорошо, но в любом случае важно установить правильный родитель. Я расширил свой ответ (подробности см. в ответе пользователя 1034749) - person Ilya; 10.11.2015
comment
@llya, на самом деле я пытаюсь реализовать окно свойств, содержащее виджет дерева. Каждый элемент виджета дерева содержит виджет (установленный с помощью setItemWidget() ). Окно свойств показывает свойство объекта, который я выбираю. Допустим, виджет дерева показывает свойства объекта A, я выбираю объект B, и когда я снова выбираю объект A, я удаляю элементы в виджете дерева (который на самом деле принадлежит объекту B) и добавляю элементы объекта A. снова. Когда я это делаю, у него нет виджета элемента, который я установил изначально. Поэтому я снова устанавливаю виджет элемента, что вызывает сбой. - person Sankar; 10.11.2015
comment
Что означает то, что на самом деле принадлежит Объекту Б? Если это означает, что на самом деле соответствует этому, все в порядке (т.е. если вы создаете новые виджеты перед вызовом setItemWidget). Но если вы используете указатели на эти объекты (части объекта B) в качестве аргументов setItemWidget, это неправильно, потому что в этом случае вы теряете право собственности (и это причина сбоя). - person Ilya; 10.11.2015
comment
Нет, я не использую указатели объекта B в качестве аргументов для setItemWidget. Я использовал один и тот же виджет в качестве аргумента для setItemWidget два раза. Как вы сказали, он удаляется, когда я второй раз вызываю setItemWidget. Это может быть причиной аварии. В любом случае, мне нужно искать другой подход для моего варианта использования. Спасибо! - person Sankar; 10.11.2015