如何从QML Repeater访问QAbstractTableModel数据

时间:2018-03-23 17:19:22

标签: c++ qt qml

我几天都在努力想弄清楚如何在QML窗口中显示一些非常简单的数据。我意识到有很多方法可以完成这项任务,在这种情况下,我更愿意了解如何使用QAbstractTableModel。

我有一行数据,每行包含两个项目,一个名称和一个值(名称/值或键/值对)。我已将QAbstractTableModel子类化,以将此数据传递给QML。这是我到目前为止的代码;它主要基于可以在这里找到的教程(也很老):https://doc.qt.io/archives/4.6/itemviews-addressbook.html

databridge.h

#include <QObject>
#include <QAbstractTableModel>
#include <QPair>

class DataBridge : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit DataBridge();
    explicit DataBridge(QList<QPair<QString, QString>> listOfPairs);

    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    bool insertRows(int row, int count, const QModelIndex &parent);
    bool removeRows(int row, int count, const QModelIndex &parent);
    Qt::ItemFlags flags(const QModelIndex &index) const;
    QList<QPair<QString, QString>> getList();

signals:

public slots:

private:
    QList<QPair<QString, QString>> m_listOfPairs;

};

#endif // DATABRIDGE_H

databridge.cpp

#include "databridge.h"

DataBridge::DataBridge()
{}
DataBridge::DataBridge(QList<QPair<QString, QString> > listOfPairs)
{  m_listOfPairs = listOfPairs; }

int DataBridge::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_listOfPairs.size();
}

int DataBridge::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    //Number of columns is always 2 in this kata
    return 2;
}

QVariant DataBridge::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();
    if(index.row() >= m_listOfPairs.size() || index.row() < 0)
        return QVariant();
    if(role == Qt::DisplayRole)
    {
        QPair<QString, QString> pair = m_listOfPairs.at(index.row());
        if(index.column() == 0)
            return pair.first;
        else
            return pair.second;
    }
    return QVariant();
}

bool DataBridge::setData(const QModelIndex &index, const QVariant &value, int role)
{
    //TODO
    return QVariant();
}

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

bool DataBridge::insertRows(int row, int count, const QModelIndex &parent)
{
    //TODO
    return true;
}

bool DataBridge::removeRows(int row, int count, const QModelIndex &parent)
{
    //TODO
    return true;
}

Qt::ItemFlags DataBridge::flags(const QModelIndex &index) const
{
    if(!index.isValid())
        return Qt::ItemIsEnabled;

    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}

QList<QPair<QString, QString> > DataBridge::getList()
{
    return m_listOfPairs;
}

的main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QPair>
#include "databridge.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    QList<QPair<QString, QString>> inserter;
    inserter.append(QPair<QString, QString>("0", "zero"));
    inserter.append(QPair<QString, QString>("1", "one"));
    inserter.append(QPair<QString, QString>("2", "two"));
    inserter.append(QPair<QString, QString>("3", "three"));
    inserter.append(QPair<QString, QString>("4", "four"));

    DataBridge * bridge = new DataBridge(inserter);
    engine.rootContext()->setContextProperty("bridge", bridge);

    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

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

    Component{
        id: myComponent
        Row{
            id: thisRow
            Text{
                text: bridge.data(index, 0)
            }
            Text{
                text: "\t.\t.\t.\t"
            }
            Text{
                text: bridge.data(index, 0)
            }
        }
    }

    Column{
        id: thisColumn
        anchors.horizontalCenter: parent.horizontalCenter
        Repeater{
            id: myRepeater
            delegate: myComponent
            model: bridge
        }
    }

    Component.onCompleted: {
        console.log("DEBUG main.qml");
    }
}

请在databridge.cpp中忽略其中包含TODO的功能。为了简洁起见,我没有包括尸体。

我面临的第一个问题是,当main.qml中的转发器调用bridge.data(index,0)时,在数据函数的第一个if语句中确定索引无效(如果(!index.isValid())。我不确定为什么会发生这种情况。我能看到的第二个问题,虽然我还没有达到这个目的,但是如果我和我怎么能告诉数据功能呢? #39; m调用第0列还是第1列?它稍后在函数中检查它,并返回与所请求的列相关的对。我猜测在myComponent中,我需要更具体的东西来请求来自无论哪一列,但我不确定那会是什么?

对此的任何帮助都将非常感激。提前谢谢!

QModelIndex Documentation

Another link to the example referenced at the top

QAbstractTableModel Documentation

Qt Role Enum Documentation

1 个答案:

答案 0 :(得分:0)

我能够找到解决方案,但我不确定它是否正确。我在databridge类中添加了一个函数,该函数从QML获取整数输入,找到相应的QModelIndex,然后以这种方式从模型中提取数据。这就是代码的样子:

来自databridge.cpp

QString DataBridge::getThisItem(int index, int column)
{
    QModelIndex currentIndex = QAbstractTableModel::index(index, column);
    QString retVal = data(currentIndex, 0).toString();
    return retVal;
}

对应的QML中继器更改

Component{
    id: myComponent
    Row{
        id: thisRow
        Text{
            text: bridge.getThisItem(index, 0)
        }
        Text{
            text: "\t.\t.\t.\t"
        }
        Text{
            text: bridge.getThisItem(index, 1)
        }
    }
}

这会产生所需的输出,即:Output of program

我很想知道这是一个很好的实现,还是有更好的方法来实现这一点。再次感谢!