将QAbstractTableModel与Qml TableView一起使用仅显示第一列 [英] Using a QAbstractTableModel with a Qml TableView only displays the 1st column

查看:93
本文介绍了将QAbstractTableModel与Qml TableView一起使用仅显示第一列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将QAbstractTableModel(派生自类)与Qml TableView一起使用;

I'm trying to use a (class derived from) QAbstractTableModel with a Qml TableView;

但是,仅显示第一列.

原因是非零列未调用QVariant MyModel :: data(const QModelIndex& index,int role),但我不明白为什么.

The reason is QVariant MyModel::data(const QModelIndex &index, int role) isn't called for non-zero columns, but I don't understand why.

但是QTableView可以正常工作.

A QTableView works fine however.

我已经制作了一个单独的简单项目来重现我的问题:

I've made a separate, simple project that reproduce my issue:

MyModel.h:

MyModel.h :

#ifndef MYMODEL_H
#define MYMODEL_H

#include <QObject>
#include <QAbstractTableModel>
#include <QList>
#include <QString>
#include <QDebug>

struct SimpleData
{
    QString m_one;
    qint32 m_two;
    qreal m_three;
};

class MyModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit MyModel();//MyData *the_data);
    int rowCount(const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE;
    int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;

    QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
signals:

public slots:
    void theDataChanged();

private:
   QList<SimpleData> m_the_data;

};

#endif // MYMODEL_H

mymodel.cpp: #include"mymodel.h"

mymodel.cpp: #include "mymodel.h"

MyModel::MyModel() : QAbstractTableModel(0)
{
    m_the_data << SimpleData{"Alpha", 10, 100.0}
               << SimpleData{"Beta", 20, 200.0}
               << SimpleData{"Gamma", 30, 300.0}
               << SimpleData{"Delta", 40, 400.0};
}

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

int MyModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 3;
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    // Check DisplayRole
    if(role != Qt::DisplayRole)
    {
        return QVariant();
    }

    // Check boudaries
    if(index.column() < 0 ||
            columnCount() <= index.column() ||
            index.row() < 0 ||
            rowCount() <= index.row())
    {
        qDebug() << "Warning: " << index.row() << ", " << index.column();
        return QVariant();
    }

    // Nominal case
     qDebug() << "MyModel::data: " << index.column() << "; " << index.row();
    switch(index.column())
    {
        case 0:
            return m_the_data[index.row()].m_one;
        case 1:
            return  m_the_data[index.row()].m_two;
        case 2:
            return  m_the_data[index.row()].m_three;
        default:
            qDebug() << "Not supposed to happen";
            return QVariant();
    }
}

QHash<int, QByteArray> MyModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[0] = "one";
    roles[1] = "two";
    roles[2] = "three";
    return roles;

}

void MyModel::theDataChanged()
{
    //TODO
}

main.qml:

import QtQuick 2.1
import QtQuick.Controls 1.0

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

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }
TableView {

    anchors.fill: parent

    TableViewColumn {title: "1"; role: "one"; width: 70 }
    TableViewColumn {title: "2"; role: "two"; width: 70   }
    TableViewColumn {title: "3"; role: "three"; width: 70 }

    model: theModel

}

}

main.cpp:

#include <QtQml>
#include <QQmlApplicationEngine>
#include <QApplication>
#include <QQuickWindow>
#include <QTableView>

#include "mymodel.h"

int main(int argc, char *argv[])
{
    // Application :
    QApplication app(argc, argv);

    // Data stuff :
    //MyData data(&app);
    MyModel model;



 // UI :
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("theModel", &model);

    engine.load(QUrl("qrc:/qml/main.qml"));
    QList<QObject*> temp = engine.rootObjects();
    QObject *topLevel = temp.value(0);
    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
    if ( !window ) {
        qWarning("Error: Your root item has to be a Window.");
        return -1;


 }

    // Display the main.qml, which show the model:
    window->show();

    // Same, using a QTableView:
    QTableView view;;
    view.setModel(&model);
    view.show();

    return app.exec();
}

有关TableView的qDebug输出(行,然后是列):

qDebug output about the TableView (row, then column):

MyModel::data:  0 ;  0 
MyModel::data:  0 ;  0 
MyModel::data:  0 ;  1 
MyModel::data:  0 ;  1 
MyModel::data:  0 ;  2 
MyModel::data:  0 ;  2 
MyModel::data:  0 ;  3 
MyModel::data:  0 ;  3 

有关QTableVierw的qDebug输出:

qDebug output about the QTableVierw:

MyModel::data:  0 ;  0 
MyModel::data:  0 ;  0 
MyModel::data:  0 ;  0 
MyModel::data:  1 ;  0 
MyModel::data:  2 ;  0 
MyModel::data:  0 ;  1 
MyModel::data:  1 ;  1 
MyModel::data:  2 ;  1 
MyModel::data:  0 ;  2 
MyModel::data:  1 ;  2 
MyModel::data:  2 ;  2 
MyModel::data:  0 ;  3 
MyModel::data:  1 ;  3 
MyModel::data:  2 ;  3 

我尝试过的笔记/东西:

Notes / stuff I tried:

  • 在我提供的代码中,我可以使用QQmlListProperty;但是我的实际代码更复杂

  • In the code I gave, I could use a QQmlListProperty; however my actual code is more complex

  • 实际上是在查询数据,
  • 我没有SimpleData类
  • 我基本上是使用QAbstractTableModel作为代理. 结果,我无法切换到QQmlListProperty(或等效版本)
  • the data is actually queried,
  • I don't have a SimpleData class
  • I'm basically using the QAbstractTableModel as a proxy. As a consequence, I can't switch to a QQmlListProperty (or equivalent)

有一个用于检查模型的项目ModelTest,但是它不适用于Qt 5.2.

there was a project to check models, ModelTest, however it does not work with Qt 5.2.

数据类型(QString,qreal)不是问题:交换仍然仅显示第一列.

the type of data (QString, qreal) isn't an issue: swapping still display only the 1st column.

相关链接:

http://qt-project.org/doc/qt-5/QAbstractTableModel.html

http://qt-project.org/doc/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel

提前谢谢!

规格:Windows 7,Qt 5.2,Mingw 4.8,Qt Creator 3.0

Specs: Windows 7, Qt 5.2, Mingw 4.8, Qt Creator 3.0

推荐答案

TableViewColumn API建议通过角色而不是列(例如,一个",两个"和三个")检索列中的数据,而传递的列将始终为0.除Qt :: DisplayRole之外的所有内容都返回QVariant(). Qt :: DisplayRole为0,转换为int.在角色名称中,将0的名称设置为"one",这就是为什么您碰巧看到"one"(DisplayRole)的原因.

The TableViewColumn API suggests that the data from the column is retrieved via roles instead of columns, i.e. "one", "two", and "three", while the column passed will be always 0. You return QVariant() for everything but Qt::DisplayRole. Qt::DisplayRole is 0, converted to int. In rolenames, you set the name for 0 to "one", so that's why you happen to see something for "one" (DisplayRole).

因此,要解决此问题,您必须返回一,二和三的值.我建议在标题中定义一个自定义角色枚举:

So to fix this, you must return something for one, two, and three. I'd suggest to define a custom roles enum in the header:

//In class MyModel:
enum Role {
    OneRole=Qt::UserRole,
    TwoRole,
    ThreeRole
};

定义这样的角色名称:

QHash<int, QByteArray> MyModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[OneRole] = "one";
    roles[TwoRole] = "two";
    roles[ThreeRole] = "three";
    return roles;
}

请注意,我从Qt :: UserRole而不是0开始.这避免了与预定义角色(例如Qt :: DisplayRole)发生冲突.

Note that I started with Qt::UserRole instead of 0. That avoids collision with predefined roles such as Qt::DisplayRole.

然后在data()中返回1、2和3的值:

Then return something for One, Two and Three, in data():

...
switch(role)
{
    case OneRole:
        return m_the_data[index.row()].m_one;
    case TwoRole:
        return m_the_data[index.row()].m_two;
    case ThreeRole:
        return m_the_data[index.row()].m_three;
}
...

现在您应该看到数据了.

Now you should see the data.

QtQuickControls的TableView/TableViewColumn似乎对角色和列进行了某种不幸和令人困惑的混合:虽然命名让我们想到了模型列(但实际上它们是在这里引用视图的列),但只能检索数据通过不同的角色,列固定为0.(对我来说,TableViewColumn中应该有另一个可选属性"column".) 在C ++ QAbstractItemModel/QTableView的处理方式(其中很自然要处理多个列)和QtQuick视图之间有些冲突,QtQuick视图都只使用角色来引用数据,通常根本不支持多列(ListView, GridView).

It seems that the TableView/TableViewColumn from QtQuickControls does a somewhat unfortunate and confusing mix of role and columns: While the naming let's one think of model columns (but they actually refer to the view's columns here), one can retrieve data only via different roles, with the column being fixed to 0. (To me there should be another optional property "column" in TableViewColumn.) It's a bit of a clash between the C++ QAbstractItemModel/QTableView way of things, where multiple columns are a natural thing to do, and QtQuick views, which all use only roles to refer to data, often not supporting multiple columns at all (ListView, GridView).

这篇关于将QAbstractTableModel与Qml TableView一起使用仅显示第一列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆