上两节中介绍了如何构造model,并与数据关联,在不同的显示控件中展示数据的方式。都是以只读方式读取数据,然后显示出来,没有对数据源进行写操作。今天将以第2节为基础,实现修改并显示数据源的功能。这里开始引入了代理(Delegate)的概念。
代理在模型和视图中间桥梁的作用,它可以渲染数据项,并通知模型和视图进行数据更新。
实现修改第2节中的数据项的思路:
1.双击任何一个空白处,弹出一个LineEdit;
2.获取原先显示的数据到LineEdit控件中,编辑数据;
3.将新的数据回写到模型和二维数组中,视图和模型自动就会关联并显示新的数据。
下面开始写代码:
一、QAbstractItemDelegate是模型/视图框架中代理的基类。默认的代理实现由QStyledItemDelegate类提供。我们实现一个类LineEditDelegate,继承自QStyledItemDelegate。
class LineEditDeleget : public QStyledItemDelegate
{
public:
QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const;
void setEditorData(QWidget * editor, const QModelIndex & index) const;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
};
//创建编辑器,这些编辑器是一些控件,如Label,LineEdit,Combox等
QWidget *LineEditDeleget::createEditor(QWidget * parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
{
QLineEdit *line = new QLineEdit(parent);
return line;
}
//从model中取出数据,放到编辑器中
void LineEditDeleget::setEditorData(QWidget * editor, const QModelIndex & index) const
{
QLineEdit *lineEdit = static_cast(editor);
QString str = index.model()->data(index,Qt::DisplayRole).toString();//获取model中的数据,角色为DisplayRole
lineEdit->setText(str);
}
//将编辑器中的数据更新到model中
void LineEditDeleget::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
QLineEdit *lineEdit = static_cast(editor);
model->setData(index,lineEdit->text(),Qt::EditRole);
}
我们通过重载了3个函数,createEditor函数中创建了一个LineEdit控件,当双击表格项时该LineEdit控件就会显示出来;接下来,我们要把原先model中显示的数据放到LineEdit控件中,主要是通过index下标来获取值,由setEditorData函数实现。最后,修改的新数据,目前只是存在于LineEdit控件上,并没有写入model中。通过setModelData函数,将对应的index下标的model数据进行更新。注意,此时修改数据时的角色类型是Qt::EditRole。
二、代理类更新了model的数据,然而,model类中必须要做出相应的处理才能真正实现数据更新。TableModel类中要添加2个新的接口flags和setData。最后如下:
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
TableModel(QObject *parent = 0);
~TableModel();
//QAbstractTableModel 中3个必须重新实现的虚函数
int rowCount(const QModelIndex & parent = QModelIndex()) const;
int columnCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Qt::ItemFlags flags(const QModelIndex & index) const;
bool setData(const QModelIndex & index, const QVariant & value, int role);
private:
int num[ROW][COL];
int nn;
};
//可编辑表格添加函数
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
flags |= Qt::ItemIsEditable;
return flags;
}
bool TableModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
num[index.row()][index.column()] = value.toInt();
emit dataChanged(index, index);
return true;
}
return false;
}
flags函数作用主要表示当前的model并不是一个只读的,还有可编辑的功能。当代理类修改了model中的数据时,model类会调用setData根据修改数据时的角色进行判断,修改二维数组中的值,并发送数据改变的信号,以此完成数据的更新。