2019独角兽企业重金招聘Python工程师标准>>>
在Qt中对数据处理主要有两种方式:1)直接对包含数据的的数据项item进行操作,这种方法简单、易操作,现实方式单一的缺点,特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作,如果现实方式改变,则在改动程序过程中还需对数据进行重新编码操作,费工费资源。2)采用model/view模型,将数据--模型--视图三者串起来,通过约定的接口保证数据的正确显示和显示方式的多样性,当需要重新调整显示时,只需修改视图,保证接口不变,即可以新view显示数据。
1/2两种处理数据方式:
在此,我主要介绍model/view模式,在此以QAbstractTableModel/QTableView为例。
如果是只读模式,model只要重写以下三个方法:
//a方法:返回模型行数。
int rowCount(const QModelIndex &parent) const;
//b方法:返回模型列数。
int columnCount(const QModelIndex &parent) const;
//c方法:返回index项的role角色的数据。其中index项中可以有多个角色,每个角色都可以有一个数据。
QVariant data(const QModelIndex &index, int role) const;
如果用户要能够编辑数据(编辑模式),model还需要重写以下两个方法:
//d方法:设置模型中项的内容。
bool QAbstractItemModel::setData(const QModelIndex & index, const QVariant & value, int role= Qt::EditRole);//e方法:返回项的编辑形式,默认情况下只有ItemIsSelectable和ItemIsEnabled,如果要可编辑,需要
//添加ItemIsEditable属性。
Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex & index) const
其中a/b/c方法为纯虚函数(pure virtual method),继承的类必须由coder自己实现此方法。d/e方法为虚函数(virtual),coder在继承了此方法,实现自定义内容后可直接调用基类方法。
在此我们以《c++ gui programming with Qt4》中的trackEditor例子作一讲解。
class MyTableModel : public QAbstractTableModel
{
public:explicit MyTableModel(QList
其中“QList
MyTableModel::MyTableModel(QList
{Q_UNUSED(parent);pTracks = tracks;
}
构造函数对tracks进行赋值。
int MyTableModel::rowCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return pTracks->count();
}int MyTableModel::columnCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return 2;
}
以上2个方法返回model的行/列数,因为tracks中的数据量不确定,所以直接返回其count方法,保证每次都是最新值;
QVariant MyTableModel::data(const QModelIndex &index, int role) const
{if ( !index.isValid()) {return QVariant();}if (Qt::DisplayRole == role || Qt::EditRole == role) {if (0 == index.column()) {return pTracks->at(index.row()).getTitle();} else if (1 == index.column()) {return pTracks->at(index.row()).getDuration();}}return QVariant();
}
根据数据类型和所在列,返回不同的数据信息,当index都不属于以上两种情况时,返回QVariant对象。EditRole保证了当用户编辑数据时,数据显示的是被选中模式而不是直接消失。
bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{if ( !index.isValid()) {return false;}if (Qt::EditRole == role) {(*pTracks)[index.row()].setTitle(value.toString());emit dataChanged(index, index);return true;} else {return QAbstractTableModel::setData(index, value, role);}
}
根据coder处理和传入角色,设置index处项的值及tracks中对应处的数据并更新index的数据显示。当传入数据coder不处理时,则直接调用基类方法处理,再辞没有特别指明第几列进行编辑,因为是后面通过flags方法来设定了可编辑的列,故此处不用再特别指明。在此请注意,setData方法是判断的是Qt::EditRole角色,data方法是Qt::DisplayRole,但是保存、读取的都是tracks,这正是coder要注意的,在不同的过程时,程序所处于的角色不同,但是都操作同样的数据库(tracks),这点要注意。
Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{if (0 == index.column()) {return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);} else {return QAbstractTableModel::flags(index);}
}
model中每个项的处理标志位默认为(ItemIsEnabled | ItemIsSelectable),coder可根据要求对不同属性的项进行设置。在此设定第0列可编辑,其余列不可编辑。
程序运行结果,分别用TableView和ListView显示相同的数据:
具体代码如下:共有maindialg,mytablemodel,tack三个类,一个main运行类。具体界面文件是由Qt自己生成的ui。
track.h
#ifndef TRACK_H
#define TRACK_H#include
{
public:explicit Track(const QString& title = "", int duration = 0);QString getTitle() const;int getDuration() const;void setDuration(int duration);void setTitle(QString title);private:QString mTitle;int mDuration;
};#endif // TRACK_H
track.cpp
#include "track.h"Track::Track(const QString &title, int duration) :mTitle(title),mDuration(duration)
{}QString Track::getTitle() const
{return mTitle;
}int Track::getDuration() const
{return mDuration;
}void Track::setDuration(int duration)
{mDuration = duration;
}void Track::setTitle(QString title)
{mTitle = title;
}
mytablemodel.h
#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H#include
#include
#include "track.h"class MyTableModel : public QAbstractTableModel
{
public:explicit MyTableModel(QList
};#endif // MYTABLEMODEL_H
mytablemodel.cpp
#include "mytablemodel.h"MyTableModel::MyTableModel(QList
{Q_UNUSED(parent);pTracks = tracks;
}int MyTableModel::rowCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return pTracks->count();
}int MyTableModel::columnCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return 2;
}QVariant MyTableModel::data(const QModelIndex &index, int role) const
{if ( !index.isValid()) {return QVariant();}if (Qt::DisplayRole == role) {if (0 == index.column()) {return pTracks->at(index.row()).getTitle();} else if (1 == index.column()) {return pTracks->at(index.row()).getDuration();}}return QVariant();
}QVariant MyTableModel::headerData(int section,Qt::Orientation orientation,int role) const
{/*if (Qt::Vertical == orientation) {return QVariant();}*/if (Qt::DisplayRole == role && Qt::Horizontal == orientation) {switch (section) {case 0:return "first";case 1:return "second";}}return QVariant();
}Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{if (0 == index.column()) {return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);} else {return QAbstractTableModel::flags(index);}
}bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{if ( !index.isValid()) {return false;}if (Qt::EditRole == role) {(*pTracks)[index.row()].setTitle(value.toString());emit dataChanged(index, index);return true;} else {return QAbstractTableModel::setData(index, value, role);}
}
maindialog.h
#ifndef MAINDIALOG_H
#define MAINDIALOG_H#include
#include
#include
#include "mytablemodel.h"namespace Ui {
class MainDialog;
}class MainDialog : public QDialog
{Q_OBJECTpublic:explicit MainDialog(QWidget *parent = 0);~MainDialog();void setTableModel(MyTableModel* model);void setListModel(MyTableModel* model);private:Ui::MainDialog *ui;QTableView* pTableView;QListView* pListView;
};#endif // MAINDIALOG_H
maindialog.cpp
#include
#include "maindialog.h"
#include "ui_maindialog.h"MainDialog::MainDialog(QWidget *parent) :QDialog(parent),ui(new Ui::MainDialog),pTableView(new QTableView(this)),pListView(new QListView(this))
{ui->setupUi(this);QVBoxLayout* layout(new QVBoxLayout(this));layout->addWidget(pTableView);layout->addWidget(pListView);setLayout(layout);setAttribute(Qt::WA_DeleteOnClose);
}MainDialog::~MainDialog()
{delete ui;
}void MainDialog::setTableModel(MyTableModel *model)
{pTableView->setModel(model);
}void MainDialog::setListModel(MyTableModel* model)
{pListView->setModel(model);
}
main.cpp
#include
#include "maindialog.h"
#include "track.h"
#include "mytablemodel.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);QList
}
完整代码: