前四章view都是被动的展示数据,本章介绍如何编辑数据。
其实编辑功能的启用也是mode控制的,mode实现setdata()和flags()就启用了编辑功能。
mymode.h
#include <QAbstractTableModel>
#include <QString>
const int COLS= 3;
const int ROWS= 2;
class MyModel : public QAbstractTableModel
{
Q_OBJECT
public:
MyModel(QObject *parent);
int rowCount(const QModelIndex &parent = QModelIndex()) const override ;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex & index) const override ;
private:
QString m_gridData[ROWS][COLS]; //holds text entered into QTableView
signals:
void editCompleted(const QString &);
};
定义了一个2行3列的二维数组m_gridData,增加了setData()和flags()函数,并添加一个信号editCompleted(),信号的目的是更新标题栏显示,是非必须的。
mymode.cpp
#include "mymodel.h"
MyModel::MyModel(QObject *parent)
:QAbstractTableModel(parent)
{
}
//-----------------------------------------------------------------
int MyModel::rowCount(const QModelIndex & /*parent*/) const
{
return ROWS;
}
//-----------------------------------------------------------------
int MyModel::columnCount(const QModelIndex & /*parent*/) const
{
return COLS;
}
//-----------------------------------------------------------------
QVariant MyModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
return m_gridData[index.row()][index.column()];
}
return QVariant();
}
//-----------------------------------------------------------------
//! [quoting mymodel_e]
bool MyModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
if (role == Qt::EditRole)
{
//save value from editor to member m_gridData
m_gridData[index.row()][index.column()] = value.toString();
//for presentation purposes only: build and emit a joined string
QString result;
for (int row= 0; row < ROWS; row++)
{
for(int col= 0; col < COLS; col++)
{
result += m_gridData[row][col] + ' ';
}
}
emit editCompleted( result );
}
return true;
}
//! [quoting mymodel_e]
//-----------------------------------------------------------------
//! [quoting mymodel_f]
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}
setData()的作用就是把参数value的值赋值给相应的数组单元,value就是界面上输入的数据,index指示输入的单元,所以role的角色必然是Qt::EditRole;变量result记录单元格数据,通过信号发出,信号会被主线程接收,显示在标题栏。用户每次编辑单元格,setData()就会被调用,对m_gridData赋值后,就会触发changeData()信号更新界面,当然这是默认行为了(也默认调用了data())。
其实真正允许编辑的标志是flag()函数,setdata()只是进行编辑;Qt的MV模型实际上是MCV模型,即还有C(控制)这一层,我们叫做委托delegate,编辑是通过委托来实现的,在创建编辑器的时候委托要检查是否允许编辑,其实就是检查mode的flags()中设置的Qt::ItemFlags属性,本例启用了Qt::ItemIsEditale就是告诉委托可以编辑数据项,这样setData()就可以工作了。
本例为了方便的在标题栏显示编辑的内容,将QTableView放在了Mainwindow上,其实这不是必须的,以下内容可以没有。
mainwindow.h
#include <QtWidgets/QMainWindow>
QT_BEGIN_NAMESPACE // QT_BEGIN_NAMESPACE / QT_END_NAMESPACE are not needed in Qt user code
class QTableView; //forward declaration
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QTableView *tableView;
public:
MainWindow(QWidget *parent = 0);
public slots:
void showWindowTitle(const QString & title);
};
mainwindow.cpp
#include <QTableView>
#include "mainwindow.h"
#include "mymodel.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
tableView = new QTableView(this);
setCentralWidget(tableView);
QAbstractTableModel *myModel = new MyModel(this);
tableView->setModel(myModel);
//transfer changes to the model to the window title
connect(myModel, SIGNAL(editCompleted(const QString &)), this, SLOT(setWindowTitle(const QString &)));
}
void MainWindow::showWindowTitle(const QString & title)
{
setWindowTitle(title);
}
运行效果如下: