Модель C++ для QML TreeView

Из-за отсутствия какой-либо другой демонстрации Qt я использую SimpleTreeModeldemo виджетов Qt для реализации модели C++ для моего QML TreeView. Я определил роли, чтобы QML мог их использовать, но у меня возникли проблемы с их подключением к фактическим данным модели.

Что мне также кажется интересным, так это то, что демонстрация виджетов (C++) работает нормально, но TreeModel, похоже, не сохраняет данные в качестве своей переменной-члена.. заставляет меня почесать голову. Я понял это, каждое хранилище TreeItem все его дочерние элементы, а TreeModel имеет только один rootItem, который, в свою очередь, хранит все данные в качестве своего дочернего элемента.

Класс TreeItem

class TreeItem
{
public:
    explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = 0);
    ~TreeItem();

    void appendChild(TreeItem *child);

    TreeItem *child(int row);
    int childCount() const;
    int columnCount() const;
    QVariant data(int column) const;
    int row() const;
    TreeItem *parentItem();

private:
    QList<TreeItem*> m_childItems;
    QList<QVariant> m_itemData;
    TreeItem *m_parentItem;
};

Класс TreeModel

class TreeModel : public QAbstractItemModel
{
    Q_OBJECT

public:
    enum DisplayRoles {
        TitleRole = Qt::UserRole + 1,
        SummaryRole
    };

    explicit TreeModel(const QString &data, QObject *parent = 0);
    ~TreeModel();

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

    QHash<int, QByteArray> TreeModel::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[TitleRole] = "title";
        roles[SummaryRole] = "summary";
        return roles;
    }


private:
    void setupModelData(const QStringList &lines, TreeItem *parent);

    TreeItem *rootItem;
};

Модель загружает данные из default.txt

TreeModel::TreeModel(const QString &data, QObject *parent)
    : QAbstractItemModel(parent)
{
    QList<QVariant> rootData;
    rootData << "Title" << "Summary";
    rootItem = new TreeItem(rootData);
    setupModelData(data.split(QString("\n")), rootItem);
}

void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
{
    QList<TreeItem*> parents;
    QList<int> indentations;
    parents << parent;
    indentations << 0;

    int number = 0;

    while (number < lines.count()) {
        int position = 0;
        while (position < lines[number].length()) {
            if (lines[number].mid(position, 1) != " ")
                break;
            position++;
        }

        QString lineData = lines[number].mid(position).trimmed();

        if (!lineData.isEmpty()) {
            // Read the column data from the rest of the line.
            QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts);
            QList<QVariant> columnData;
            for (int column = 0; column < columnStrings.count(); ++column)
                columnData << columnStrings[column];

            if (position > indentations.last()) {
                // The last child of the current parent is now the new parent
                // unless the current parent has no children.

                if (parents.last()->childCount() > 0) {
                    parents << parents.last()->child(parents.last()->childCount()-1);
                    indentations << position;
                }
            } else {
                while (position < indentations.last() && parents.count() > 0) {
                    parents.pop_back();
                    indentations.pop_back();
                }
            }

            // Append a new item to the current parent's list of children.
            parents.last()->appendChild(new TreeItem(columnData, parents.last()));
        }

        ++number;
    }
}

Моя проблема в этой функции, как мне связать роли с данными, которые хранятся в rootItem?. Обратите внимание, что titleString и summaryString являются возможными предлагаемыми функциями (если они нужны), но я не знаю, что в них написать, чтобы получить доступ к данным!

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.isValid() && role >= TitleRole) {
        switch (role) {
        case TitleRole:
            return QVariant(titleString(rootItem(index))); // get title through rootItem?
        case SummaryRole:
            return QVariant(summaryString(rootItem(index))); // get summary through rootItem?
        }
    }

    if (role != Qt::DisplayRole)
        return QVariant();

    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

    return item->data(index.column());
}

default.txt имеет следующие данные, но они же доступны и в самой демо-версии Qt Creator.

Getting Started             How to familiarize yourself with Qt Designer
    Launching Designer          Running the Qt Designer application
    The User Interface          How to interact with Qt Designer

Designing a Component           Creating a GUI for your application
    Creating a Dialog           How to create a dialog
    Composing the Dialog        Putting widgets into the dialog example
    Creating a Layout           Arranging widgets on a form
    Signal and Slot Connections     Making widget communicate with each other

Using a Component in Your Application   Generating code from forms
    The Direct Approach         Using a form without any adjustments
    The Single Inheritance Approach Subclassing a form's base class
    The Multiple Inheritance Approach   Subclassing the form itself
    Automatic Connections       Connecting widgets using a naming scheme
        A Dialog Without Auto-Connect   How to connect widgets without a naming scheme
        A Dialog With Auto-Connect  Using automatic connections

Form Editing Mode           How to edit a form in Qt Designer
    Managing Forms          Loading and saving forms
    Editing a Form          Basic editing techniques
    The Property Editor         Changing widget properties
    The Object Inspector        Examining the hierarchy of objects on a form
    Layouts             Objects that arrange widgets on a form
        Applying and Breaking Layouts   Managing widgets in layouts 
        Horizontal and Vertical Layouts Standard row and column layouts
        The Grid Layout         Arranging widgets in a matrix
    Previewing Forms            Checking that the design works

Using Containers            How to group widgets together
    General Features            Common container features
    Frames              QFrame
    Group Boxes             QGroupBox
    Stacked Widgets         QStackedWidget
    Tab Widgets             QTabWidget
    Toolbox Widgets         QToolBox

Connection Editing Mode         Connecting widgets together with signals and slots
    Connecting Objects          Making connections in Qt Designer
    Editing Connections         Changing existing connections

Мой вывод показывает то же количество строк, что и в демонстрации виджетов, за исключением того, что текста нет. Такое впечатление, что это просто неправильно связано с ролями или роли не связаны с днем. Прикрепляю скрин своего вывода.

введите здесь описание изображения


person zar    schedule 22.01.2016    source источник
comment
filesystembrowser кажется более подходящим - ищите древовидную структуру на экране примеров QtCreator   -  person CapelliC    schedule 24.01.2016
comment
@CapelliC Это то, с чего я начал, функция data там работает со стандартным QFileSystemModel и вызывает только fileInfo(index) для извлечения рассматриваемого файла. Здесь модель данных — это пользовательские данные. Это действительно вопрос, как пройти эти данные. Мне нужно, чтобы эта структура работала, потому что мой реальный проект будет хранить данные таким же образом.   -  person zar    schedule 24.01.2016
comment
Вот у вас есть хороший пример для начала. TreeItem следует изменить, чтобы учесть ваши новые роли.   -  person Tarod    schedule 25.01.2016


Ответы (1)


Просто так, если кто-то пытается сделать то же самое, я понял это, и вот ответ. Метод данных модели должен читаться следующим образом.

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

    if (index.isValid() && role >= TitleRole) {
        switch (role) {
        case TitleRole:
            return item->data(0);
        case SummaryRole:
            return item->data(1);
        }
    }

    if (role != Qt::DisplayRole)
        return QVariant();

    return item->data(index.column());
}

TreeItem можно изменить в реальном приложении для хранения определенных данных, и в этом случае вышеуказанный метод будет указывать на эти данные, а не на подход с номером столбца.

person zar    schedule 25.01.2016
comment
Отлично, zadane :) Спасибо, что поделились! Удачного кодирования! - person Tarod; 26.01.2016