WedX - журнал о программировании и компьютерных науках

как перенести QAbstractItemModel в QtQuick (без определения ItemDelegate)

У меня есть модель дерева QAbstractItemModel для дерева сущностей Qt3D:

qt3dentitytreemodel.h:

#define QT3DENTITYTREEMODEL_H

#include <QAbstractItemModel>
#include <Qt3DCore/QEntity>

class Qt3DEntityTreeModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    Q_PROPERTY(Qt3DCore::QEntity * rootEntity READ rootEntity WRITE setRootEntity NOTIFY rootEntityChanged)

    explicit Qt3DEntityTreeModel(QObject *parent = nullptr);

    void setRootEntity(Qt3DCore::QEntity *rootEntity);
    Qt3DCore::QEntity * rootEntity() const;

    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &child) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    Qt::ItemFlags flags(const QModelIndex &index) const override;

signals:
    void rootEntityChanged(Qt3DCore::QEntity *rootEntity);

private:
    Qt3DCore::QEntity *rootEntity_;
};

#endif // QT3DENTITYTREEMODEL_H

qt3dentitytreemodel.cpp:

#include "qt3dentitytreemodel.h"

Qt3DEntityTreeModel::Qt3DEntityTreeModel(QObject *parent)
    : QAbstractItemModel(parent)
{
}

void Qt3DEntityTreeModel::setRootEntity(Qt3DCore::QEntity *rootEntity)
{
    qDebug() << "Qt3DEntityTreeModel::setRootEntity" << rootEntity;

    auto old = rootEntity_;

    rootEntity_ = rootEntity;

    if(rootEntity_ != old)
        emit rootEntityChanged(rootEntity);
}

Qt3DCore::QEntity * Qt3DEntityTreeModel::rootEntity() const
{
    return rootEntity_;
}

QModelIndex Qt3DEntityTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if(!rootEntity_) return {};
    if(column != 0) return {};
    if(!parent.isValid())
    {
        if(row == 0) return createIndex(0, 0, rootEntity_);
    }
    else
    {
        auto entity = reinterpret_cast<Qt3DCore::QEntity*>(parent.internalPointer());
        if(!entity) return {};

        return createIndex(row, column, entity->childNodes().at(row));
    }
    return {};
}

QModelIndex Qt3DEntityTreeModel::parent(const QModelIndex &child) const
{
    if(!rootEntity_) return {};
    if(!child.isValid()) return {};

    auto entity = reinterpret_cast<Qt3DCore::QEntity*>(child.internalPointer());
    if(!entity) return {};

    auto parent = entity->parentNode();
    if(!parent) return {};

    auto grandParent = parent->parentNode();
    if(!grandParent) return createIndex(0, 0, parent);

    return createIndex(grandParent->childNodes().indexOf(parent), 0, parent);
}

QVariant Qt3DEntityTreeModel::data(const QModelIndex &index, int role) const
{    
    if(!rootEntity_) return {};
    if(!index.isValid()) return {};
    if(role != Qt::DisplayRole && role != DisplayRole) return {};

    auto entity = reinterpret_cast<Qt3DCore::QEntity*>(index.internalPointer());
    if(!entity) return {};

    QString data = entity->metaObject()->className();
    if(!entity->objectName().isEmpty())
            data += QString(" \"%1\"").arg(entity->objectName());
    return data;
}

QVariant Qt3DEntityTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    return {};
}

int Qt3DEntityTreeModel::rowCount(const QModelIndex &parent) const
{
    if(!parent.isValid()) return 1;

    auto entity = reinterpret_cast<Qt3DCore::QEntity*>(parent.internalPointer());
    if(!entity) return 0;
    return entity->childNodes().count();
}

int Qt3DEntityTreeModel::columnCount(const QModelIndex &parent) const
{
    return 1;
}

Qt::ItemFlags Qt3DEntityTreeModel::flags(const QModelIndex &index) const
{
    return {};
}

который отлично работает при отображении в QTreeView (QtWidgets):

auto treeView = new QTreeView();
auto treeModel = new Qt3DEntityTreeModel(treeView);
treeModel->setRootEntity(rootEntity);
treeView->setModel(treeModel);
treeView->resize(640, 480);
treeView->show();

скриншот

однако при использовании в QtQuick Controls TreeView я не вижу текст элемента и даже не могу развернуть элемент корневого дерева:

Item {
    ...

    Qt3DEntityTreeModel {
        id: entityTreeModel
        rootEntity: root
    }

    TreeView {
        model: entityTreeModel
        TableViewColumn {
            title: "Name"
            width: 200
        }
    }

    Scene3D {
        id: scene3d

        Entity {
            id: root
            ...
        }
    }
}

скриншот

Я также попытался явно определить роль в Qt3DEntityTreeModel:

qt3dentitytreemodel.h:

enum Roles {
    DisplayRole = Qt::UserRole + 1
};
QHash<int, QByteArray> roleNames() const override;

qt3dentitytreemodel.cpp:

QVariant Qt3DEntityTreeModel::data(const QModelIndex &index, int role) const
{    
    if(!rootEntity_) return {};
    if(!index.isValid()) return {};
    if(role != Qt::DisplayRole && role != DisplayRole) return {};
    ...
}

QHash<int, QByteArray> Qt3DEntityTreeModel::roleNames() const
{
    QHash<int, QByteArray> result;
    result.insert(DisplayRole, QByteArrayLiteral("display"));
    return result;
}

и определите соответствующее свойство роли в столбце QtQuick TreeView:

TreeView {
    model: entityTreeModel
    TableViewColumn {
        title: "Name"
        role: "display"
        width: 200
    }
}

но все равно ничего не показывает.

Есть ли что-то еще, чтобы иметь возможность использовать пользовательскую абстрактную модель элемента с TreeView QtQuick?


Ответы:


1

Я думаю, что нашел объяснение: модель создается до того, как дерево сущностей Qt3D «готово».

Если я создаю модель на С++ после загрузки представления, а затем устанавливаю модель как свойство контекста, она правильно отображается в TreeView QML:

QQuickView view;
view.resize(500, 500);
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:/main.qml"));

auto rootObject = view.rootObject();
auto rootEntity = rootObject->findChild<Qt3DCore::QEntity*>("theRootEntity");
qDebug() << "rootEntity:" << rootEntity;

auto treeModel = new Qt3DEntityTreeModel(&app);
treeModel->setRootEntity(rootEntity);

view.rootContext()->setContextProperty("theModel", treeModel);

view.show();

Основная проблема заключается в том, что моя модель не отслеживает обновления дерева сущностей Qt3D и не отражает такие обновления.

24.02.2020
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]