【问题标题】:QtQuick TableView not working with C++-QAbstractTableModelQtQuick TableView 不适用于 C++-QAbstractTableModel
【发布时间】:2015-02-23 15:58:31
【问题描述】:

我试图让 Qt 模型/视图架构与 QML 视图一起工作,但无论出于何种原因,它只能部分工作。

什么有效:

  • 行数
  • 数据
  • 角色名称

不工作:

  • columnCount(方法调用了,但是好像没有效果,只要是>0)
  • headerData(这实际上应该设置列标题吗?所有示例都在QML中设置标题)
  • 标志
  • 设置数据

我正在尝试做的(已经有几个星期了),是创建一个简单的 ApplicationView,其中包含一个 TableView 和一个 C++ 模型,它可以由视图编辑。

现在只能选择整行,而不是单个单元格。表格数据似乎根本不可编辑。谁能给个提示?

ma​​in.qml

import QtQuick 2.3
import QtQuick.Controls 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    TableView {
        model: theModel
        TableViewColumn {
            role: "nameRole"
            width: 75
        }
        TableViewColumn {
            role: "ageRole"
            width: 50
        }
    }
}

ModelItem.hpp

#ifndef MODELITEM
#define MODELITEM

#include <QString>

struct ModelItem {
    ModelItem(QString name_, int age_)
        : name(name_), age(age_) {}
    QString name;
    int age;
};

#endif // MODELITEM

TableModel.hpp

#ifndef TABLEMODEL_HPP
#define TABLEMODEL_HPP

#include <QAbstractTableModel>
#include "ModelItem.hpp"

class TableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    TableModel(QObject *parent = 0);

    //works
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;

    //does not work
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

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

    Qt::ItemFlags flags(const QModelIndex &index) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
    QList<ModelItem*> items;
};

#endif // TABLEMODEL_HPP

TableModel.cpp

#include "TableModel.hpp"

TableModel::TableModel(QObject *parent)
    : QAbstractTableModel(parent) {
    items.append(new ModelItem("Hugo",33));
    items.append(new ModelItem("Egon",34));
    items.append(new ModelItem("Balder",66));
    qDebug("TableModel initialisiert");
}


int TableModel::columnCount(const QModelIndex &parent) const {
    Q_UNUSED(parent);
    qDebug("columnCount");
    return 2;
}

int TableModel::rowCount(const QModelIndex &parent) const {
    Q_UNUSED(parent);
    qDebug("rowCount");
    return items.count();
}

QVariant TableModel::data(const QModelIndex &index, int role) const {
    qDebug("data");
    switch (role) {
        case NameRole: return items[index.row()]->name;
        case AgeRole: return items[index.row()]->age;
    }
}

QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const {
    qDebug("headerData");
    switch (role) {
        case NameRole: return "1";
        case AgeRole: return "2";
    };
    return QVariant();
}

QHash<int, QByteArray> TableModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[NameRole] = "nameRole";
    roles[AgeRole] = "ageRole";
    qDebug("roleNames initialised");

    return roles;
}

Qt::ItemFlags TableModel::flags(const QModelIndex &index) const {
    qDebug("--flags called--");
    return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}

bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
    qDebug("setData called");
    switch (role) {
        case NameRole: items[index.row()]->name = value.toString();
        case AgeRole: items[index.row()]->age = value.toInt();
    }
    emit dataChanged(index, index);
    return true;
}

ma​​in.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "TableModel.hpp"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;

    TableModel model;
    engine.rootContext()->setContextProperty("theModel", &model);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

【问题讨论】:

  • 感谢 Marc 参加 SSCCE。我不擅长 qml,但赞成。

标签: qt tableview qml


【解决方案1】:

上面的答案很好地涵盖了一切。我只想补充几点:

  • 在 QML 中,您可以简单地在项目委托中执行 model.role = value,而不必手动调用 setData()
  • 几个QAbstractItemModel 方法,包括setData(),已在Qt 5.5 中生成Q_INVOKABLEhttps://codereview.qt-project.org/#/c/107171/

【讨论】:

  • 您能否为上述上下文中的 model.role=value 提供一个示例?您是否必须为每个项目 tableview 委托单独设置角色值,或者这可以应用于 itemDelegate?另外,如果 setDate 设置为 Q_INVOKABLE 你如何从 QML 调用它?
【解决方案2】:

columnCountrowCountQAbstractItemModel::index方法中调用,在data方法之前被TableView调用。

QModelIndex QAbstractTableModel::index(int row, int column, const QModelIndex &parent) const
{
    return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex();
}

bool QAbstractItemModel::hasIndex(int row, int column, const QModelIndex &parent) const
{
    if (row < 0 || column < 0)
        return false;
    return row < rowCount(parent) && column < columnCount(parent);
}

columnCount无效,只要>0,因为TableView调用了index方法,column总是等于0。

headerDataflags 不会影响 QML TableView。您只能在 QML 端设置标题。要创建可编辑的 TableView,您应该实现您的自定义 itemDelegate

ma​​in.qml

ApplicationWindow {
    visible: true
    id: root
    Component {
        id: editableDelegate
        Item {
            Text {
                width: parent.width
                anchors.margins: 4
                anchors.left: parent.left
                anchors.verticalCenter: parent.verticalCenter
                elide: styleData.elideMode
                text: styleData.value !== undefined ? styleData.value : ""
                color: styleData.textColor
                visible: !styleData.selected
            }
            Loader {
                id: loaderEditor
                anchors.fill: parent
                anchors.margins: 4
                Connections {
                    target: loaderEditor.item
                    onEditingFinished: {
                        theModel.setData(styleData.row, styleData.column, loaderEditor.item.text)
                    }
                }
                sourceComponent: styleData.selected ? editor : null
                Component {
                    id: editor
                    TextInput {
                        id: textinput
                        color: styleData.textColor
                        text: styleData.value
                        MouseArea {
                            id: mouseArea
                            anchors.fill: parent
                            hoverEnabled: true
                            onClicked: textinput.forceActiveFocus()
                        }
                    }
                }
            }
        }
    }
    TableView {
        id: table
        anchors.fill: parent
        model: theModel
        itemDelegate: editableDelegate;
        TableViewColumn {
            role: "nameRole"
            width: 75
            title: "name"
        }
        TableViewColumn {
            role: "ageRole"
            width: 50
            title: "age"
        }
    }
}

要将更改应用于您的模型,您应该实现 setData 方法,如下所示:

TableModel.h

bool setData(const QModelIndex &index, const QVariant &value, int role) {
    switch (role) {
        case NameRole: items[index.row()]->name = value.toString(); break;
        case AgeRole: items[index.row()]->age = value.toInt(); break;
    }
    emit dataChanged(index, index);
    return true;
}

Q_INVOKABLE bool setData(int row, int column, const QVariant value)
{
    int role = Qt::UserRole + 1 + column;
    return setData(index(row,0), value, role);
}

【讨论】:

  • 哇,非常感谢!我永远不会自己找到这个解决方案。
  • @MarcQ:好问题值得好答案 ;-) 谢谢,Meefte(赞成)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多