Редактирование элемента захвата QTreeWidget завершено без изменения текста

Я разрабатываю приложение Qt с QTreeWidget в форме Qt Designer. Пользователь может нажать кнопку добавления нового элемента, и новый элемент появится с именем по умолчанию, после чего пользователь должен ввести имя элемента.

Итак, это мой код:

void MyFormClass::on_addNewItemButton_clicked()
{
    auto newItem = new QTreeWidgetItem({ _defaultName });
    newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
    ui->tree->addTopLevelItem(newItem);
    ui->tree->editItem(newItem);
}

В MyFormClass я также ловлю сигнал itemChanged для выполнения некоторых операций с вновь созданным элементом и его именем:

void MyFormClass::on_tree_itemChanged(QTreeWidgetItem *item, int column)
{
    if (item->text(0).isEmpty()) {
        ...
    } else {
        ...
    }
}

И все работает нормально, за исключением случая, когда пользователь ничего не меняет и просто где-то нажимает Enter/щелкает левой кнопкой мыши. В этом случае QTreeWidget [вероятно] проверяет, что элемент не был фактически изменен, и не выдает правильный сигнал.

Итак, есть идеи, как я могу создать новый элемент, затем разрешить пользователю немедленно его редактировать и, наконец, получить любой результат редактирования (то есть то же самое, что и по умолчанию)? Может быть, использование QTreeView поможет?

Qt 5.4.2, C++11, платформы Linux/Windows

Бонусные вопросы: почему Qt разработан таким образом? Я имею в виду, разве не мое дело проверить, изменился предмет или нет? Хорошо, сигнал называется itemChanged, но почему нет сигнала editFinished или что-то в этом роде?


person serg.v.gusev    schedule 27.01.2016    source источник


Ответы (2)


Я предполагаю, что правильной областью применения этого подхода будет QTreeWidget. Итак, мы можем наследовать QTreeWidget от MyTreeWidget.

 ui->tree = new MyTreeWidget(this); // or how exactly it is initialized

В нашей работе миллион загадок. Мы можем попытаться поймать виновника, когда вещь не работает так, как мы хотим, чтобы она работала. Когда я запускаю виджет Qt, который ведет себя не так, как я ожидаю, я отслеживаю, что он делает:

bool MyTreeWidget::event(QEvent* pEvent)
{
    qDebug() << pEvent;
    // parent class method call
    return QTreeWidget::event(pEvent);
}

И затем с журналом, записанным для этого конкретного случая, я либо пытаюсь перегрузить конкретное событие (лучше и безопаснее), либо делаю это немедленно в перегруженном универсальном обработчике событий:

bool MyTreeWidget::event(QEvent* pEvent)
{
    // suppose this to be a 'culprit' event
    if (pEvent->type() == QEvent::WindowDeactivate)
        doTheRightThingHere(); // what expected to be done

    // parent class method call
    return QTreeWidget::event(pEvent);
}

Тот же подход можно применить с фильтром событий.

person Alexander V    schedule 27.01.2016

Сначала я последовал совету @AlexanderVX и поймал события. После того, как пользователь выполнил какое-либо редактирование, QEvent::ChildRemoved будет появляться во всех случаях. Я написал некоторый код, чтобы поймать это событие и обработать его.

Но после нескольких дней исследований я узнал некоторую информацию о делегатах элементов, которые могут обрабатывать редактирование пользователя, так что это мое решение:

class MyEditingDelegate : public QItemDelegate
{
    Q_OBJECT

public:
    MyEditingDelegate(QObject *parent = nullptr) : QItemDelegate(parent) {}
    virtual void setModelData(QWidget *editor, 
                              QAbstractItemModel *model, 
                              const QModelIndex &index) const
    {
        QItemDelegate::setModelData(editor, model, index);
        if (index.column() == 0) {
            emit editingFinished(index);
        }
    }

signals:
    void editingFinished(const QModelIndex &) const;
};

class MyTreeWidget : public QTreeWidget
{
public:
    MyTreeWidget(QWidget *parent = nullptr) : QTreeWidget(parent) {}
    QTreeWidgetItem *getItemFromIndex(const QModelIndex &index) const 
    {
        return itemFromIndex(index);
    }
};

MyFormClass::MyFormClass()
{
    ...

    auto editDelegate = new MyEditingDelegate(this);
    ui->tree->setItemDelegate(editDelegate);
    connect(editDelegate, 
            &MyEditingDelegate::editingFinished, 
            [this] (const QModelIndex &index) {
        auto item = ui->tree->getItemFromIndex(index);
        onItemEditingFinished(item); // this is my handler
    });

    ...
}
person serg.v.gusev    schedule 03.02.2016
comment
Даже лучше. Конечно, захват события показывает только, почему? но это не всегда отвечает как? - person Alexander V; 04.02.2016