Qt MVC
结构之 Model
模型介绍MVC
简介MVC
就是 Model-View-Control
模式的简称,包括模型层(Model
), 视图层(View
), 控制层(Controller
)。
Model
主要负责管理数据,View
主要用来显示数据,Controller
主要用来操作数据,控制 View
联动。
Qt
也采用了这个模式,模型层用 Model
,视图层用 View
,控制层改名叫了代理 Delegate
。
除了 QStandardItemModel
之外,还有一些其他集成好的特殊模型,如果我们要实现树形模型就子类化 QStandardItemModel
。
如果想实现列表模型就子类化 QAbstractListModel
,如果像实现表格模型就子类化 QAbstractTableModel
。
我们子类化 QAbstractListModel
,实现一个列表模型。
class StringListModel : public QAbstractListModel
{
Q_OBJECT
public:
StringListModel (const QStringList& strigns, QObject* parent = 0);
// explicit StringListModel(const QStringList& strings, QObject *parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const;
// 注意虚函数是的参数是下面的写法的哦,int 类型的参数是在后面的哦。不然会爆下面的 error 的
// error: main.cpp:19:21: Variable type 'StringListModel' is an abstract class 并且 qabstractitemmodel.h:191:34: unimplemented pure virtual method 'data' in 'StringListModel'
// QVariant data(int role, const QModelIndex& index) const;
QVariant data(const QModelIndex& index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
private:
QStringList stringlist;
};
这个模型类包含一个 QStringList
,用来管理数据:
int StringListModel::rowCount(const QModelIndex &parent) const
{
return stringlist.count();
}
// QVariant StringListModel::data(int role, const QModelIndex &index) const
QVariant StringListModel::data(const QModelIndex& index, int role) const
{
if(index.isValid() == false)
return QVariant();
if(index.row() >= stringlist.size())
return QVariant();
if(role == Qt::DisplayRole){
return stringlist.at(index.row());
}else{
return QVariant();
}
}
QVariant StringListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role != Qt::DisplayRole){
return QVariant();
}
if(orientation == Qt::Horizontal){
return QString("Column %1").arg(section);
}else{
return QString("Row %1").arg(section);
}
}
headerData
函数内根据水平还是垂直判断,显示表头。
data
函数内根据角色返回索引对应的数据。
在 main
函数中可以分别用一个 listview
和 treeview
显示:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// MainWindow w;
// w.show();
QStringList list;
list << "a" << "b" << "c"; // QStringList重载了 << 运算符
StringListModel model(list);
QListView listView;
listView.setModel(&model);
listView.show();
QTableView tableView;
tableView.setModel(&model);
tableView.show();
return a.exec();
}
我们为自定义的 listmodel
模型添加两个函数 flags()
和 setData()
函数。
flags
函数用来判断模型索引对应的项目的属性,通过标记按位或的方式获取。
setData
用来设置模型索引对应的项,并且设置他的编辑属性。
Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
{
if(!index.isValid()){
return Qt::ItemIsEnabled;
}
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}
如果是无效的数据则返回 ItemIsEnabled
标记,否则在原来的标记基础上增加 ItemIsEditable
。
当我们修改数据时,会触发 setData
函数, 该函数根据项的角色为 EditRole
替换原来的字符串。
bool StringListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(index.isValid() && role == Qt::EditRole){
stringlist.replace(index.row(), value.toString());
emit dataChanged(index, index);
return true;
}
return false;
}
并且发送了 dataChanged
,这个信号第一个参数为左上角的 index
,第二个参数为右下角 index
。
dataChanged
通知 View
视图刷新数据,从而完成数据的修改。
另外 Views
显示数据时会根据 data
返回的数据显示,所以要将 data
函数的显示逻辑中添加 Qt::EditRole
。
// QVariant StringListModel::data(int role, const QModelIndex &index) const
QVariant StringListModel::data(const QModelIndex& index, int role) const
{
if(index.isValid() == false)
return QVariant();
if(index.row() >= stringlist.size())
return QVariant();
if(role == Qt::DisplayRole || role == Qt::EditRole){
return stringlist.at(index.row());
}else{
return QVariant();
}
}
添加行和删除行都需要在添加和删除之前调用 begin
操作,操作完之后调用 end
操作:
// 添加行与删除行
bool StringListModel::insertRows(int position, int rows, const QModelIndex& index){
beginInsertRows(QModelIndex(), position, position + rows - 1);
for(int row = 0; row < rows; row++){
stringlist.insert(position, "");
}
endInsertRows();
return true;
}
bool StringListModel::removeRows(int position, int rows, const QModelIndex& index){
beginRemoveRows(QModelIndex(), position, position + rows - 1);
for(int row = 0; row < rows; row++){
stringlist.removeAt(position);
}
endRemoveRows();
return true;
}
接下来可以调用一下测试:
model.insertRows(3,2);
model.removeRows(0,1);
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。