文章目录
基于Qt6.2.0
以下所有代码均可在Qt安装目录:Qt安装目录/examples中找到
一.模型/视图介绍
在没有使用模型/视图的应用程序中,一个标准的表格组件是一个用户可以修改的数据元素的二维数组。表格组件能够通过读写表格组件提供的数据元素来集成到程序中。这种方法在大多数应用中都很直观而且很有用,但是当显示和编辑数据库的时候标准组件可能就有问题了。数据的两个副本必须协调:一个在组件外部,一个在组件内部。同步这两个副本的数据是开发者的职责。除了这个,显示和数据的紧密结合使得写单元测试变得更难。
而模型/视图是在处理数据集合的窗口组件中用来把数据从视图中分离出来的一种技术。MVC 把图形界面分为三个部分
- 模型(Model):用于管理数据,注意,数据不一定需要位于模型之中。
- 视图(View):就是呈现在用户面前的界面外观,视图负责把模型中的数据显示给用户
- 控制器(Controller):处理用户在界面的交互数据操作
可以通过 view(可能有多个)来修改 data,当 data 改变了之后要通知所有的 view 修改自己的显示!
二.Qt中的模型/视图控件介绍
表、列表和树控件是GUI中经常使用的组件。这些控件可以通过两种不同的方式访问其数据。传统的方式涉及用于存储数据的内部容器控件。这种方法非常直观,但在许多应用程序中,它会导致数据同步问题。第二种方法是模型/视图编程,其中控件不维护内部数据容器。他们通过标准化接口访问外部数据,因此避免了数据重复。
WidgetStandard Widget
(an item based convenience class)Model/View View Class
(for use with external data)QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeViewQColumnView shows a tree as a hierarchy of listsQComboBox can work as both a view class and also as a traditional widget
Qt中模型类的继承关系:
不同模型(的结构):
Qt中预定义好的模型类:
Model类说明QStringListModel存储字符串列表QStandardItemModel存储任意分层项目QFileSystemModel封装本地文件系统QSqlQueryModel封装SQL结果集QSqlTableModel封装SQL表QSqlRelationalTableModel用外键封装SQL表QSortFilterProxyModel排序和/或筛选其他模型
Qt中视图类的继承关系:
1. 在模型/视图控件中显示数据
视图(view)通过调用模型(model)的
rowCount()
和
calCount()
函数获取显示的行数和列数,对于每个项中要显示什么,则是通过调用模型(model)的
data()
函数。
data()
函数的参数为项的索引以及项的角色(进行什么操作),通常,我们只需要根据项的索引编写相对应的逻辑,再判断需要对项进行什么操作即可。以下例程中,我们只需要显示数据即可,所以,每当
data()
函数被调用并且操作角色为
Qt::DisplayRole
显示数据时,我们就对显示的内容进行操作。
// main.cpp#include<QApplication>#include<QTableView>#include"mymodel.h"intmain(int argc,char*argv[]){
QApplication a(argc, argv);
QTableView tableView;//定义一个视图控件
MyModel myModel;//定义一个模型
tableView.setModel(&myModel);//将模型与视图进行绑定
tableView.show();//显示视图return a.exec();}
// mymodel.h#include<QAbstractTableModel>classMyModel:publicQAbstractTableModel{
Q_OBJECT
public:MyModel(QObject *parent =nullptr);//模型的构造函数introwCount(const QModelIndex &parent =QModelIndex())constoverride;//返回模型中的行数intcolumnCount(const QModelIndex &parent =QModelIndex())constoverride;//返回模型中的列数
QVariant data(const QModelIndex &index,int role = Qt::DisplayRole)constoverride;//模型中数据的显示处理};
// mymodel.cpp#include"mymodel.h"MyModel::MyModel(QObject *parent):QAbstractTableModel(parent){}intMyModel::rowCount(const QModelIndex &/*parent*/)const{return2;}intMyModel::columnCount(const QModelIndex &/*parent*/)const{return3;}
QVariant MyModel::data(const QModelIndex &index,int role)const{if(role == Qt::DisplayRole)returnQString("Row%1, Column%2").arg(index.row()+1).arg(index.column()+1);returnQVariant();}
Qt中的Qt::ItemDataRole种类
Qt中模型/视图中的项的角色(enum Qt::ItemDataRole),有以下几种:
通用角色(以及相关类型)
Qt::ItemDataRole值描述
Qt::DisplayRole
0
以文本形式呈现的关键数据。(QString)
Qt::DecorationRole
1
以图标形式呈现为装饰的数据。(QColor, QIcon or QPixmap)
Qt::EditRole
2
适合在编辑器中编辑的格式中的数据。(QString)
Qt::ToolTipRole
三
项目工具提示中显示的数据。(QString)
Qt::StatusTipRole
4
状态栏中显示的数据。(QString)
Qt::WhatsThisRole
5
以“这是什么?”模式显示的项目数据。(QString)
Qt::SizeHintRole
13
将提供给视图的项的大小提示。(QSize)
描述外观和元数据的角色
Qt::ItemDataRole值描述
Qt::FontRole
6
使用默认委托呈现的项目所使用的字体。(QFont)
Qt::TextAlignmentRole
7
使用默认委托呈现的项的文本对齐方式。 (Qt::Alignment)
Qt::BackgroundRole
8
用于使用默认代理渲染的项目的背景画笔。(QBrush)
Qt::ForegroundRole
9
用于使用默认代理渲染的项目的前景画笔(通常为文本颜色)。(QBrush)
Qt::CheckStateRole
10
此角色用于获取项目的选中状态。(Qt::CheckState)
Qt::InitialSortOrderRole
14
此角色用于获取标题视图节的初始排序顺序。(Qt::SortOrder)。
辅助功能角色
Qt::ItemDataRole值描述
Qt::AccessibleTextRole
11
可访问性扩展和插件(如屏幕阅读器)使用的文本。(QString)
Qt::AccessibleDescriptionRole
12
出于可访问性目的对项目的描述。(QString)
用户角色
Qt::ItemDataRole值描述
Qt::UserRole
0x0100
可用于特定应用程序目的的第一个角色。
2. 更改模型/视图控件中显示数据的格式
想要更改视图中每个项的显示格式,只需要在
data()
中参数为对应的项以及操作角色时,返回对应的对象即可
// mymodel.cpp
QVariant MyModel::data(const QModelIndex &index,int role)const{int row = index.row();int col = index.column();// generate a log message when this method gets calledqDebug()<<QString("row %1, col%2, role %3").arg(row).arg(col).arg(role);switch(role){case Qt::DisplayRole:if(row ==0&& col ==1)returnQString("<--left");if(row ==1&& col ==1)returnQString("right-->");returnQString("Row%1, Column%2").arg(row +1).arg(col +1);case Qt::FontRole:if(row ==0&& col ==0){//改变cell(0,0)的字体
QFont boldFont;
boldFont.setBold(true);return boldFont;}break;case Qt::BackgroundRole:if(row ==1&& col ==2)//改变cell(1,2)的背景returnQBrush(Qt::red);break;case Qt::TextAlignmentRole:if(row ==1&& col ==1)//改变cell(1,1)的对齐方式returnint(Qt::AlignRight | Qt::AlignVCenter);break;case Qt::CheckStateRole:if(row ==1&& col ==0)//为cell(1,0)添加一个勾选框return Qt::Checked;break;}returnQVariant();}
3. 显示动态数据
为了进行动态的数据更新,我们需要先设定一个时间定时器:
MyModel::MyModel(QObject *parent):QAbstractTableModel(parent),timer(newQTimer(this)){
timer->setInterval(1000);//设置1000毫秒的定时器connect(timer,&QTimer::timeout ,this,&MyModel::timerHit);//绑定定时器的到点触发函数
timer->start();//开启定时器}
定时器触发函数中进行数据的更新,数据更新后需要释放一个
dataChanged()
信号,信号的参数为要更新项的索引和所需操作
voidMyModel::timerHit(){
QModelIndex topLeft =createIndex(0,0);//要更新的数据位置
emit dataChanged(topLeft, topLeft,{Qt::DisplayRole});//释放一个信号,让视图去更新数据}
dataChanged()
信号释放后,则会调用
data()
函数对数据进行更新
QVariant MyModel::data(const QModelIndex &index,int role)const{int row = index.row();int col = index.column();if(role == Qt::DisplayRole && row ==0&& col ==0)returnQTime::currentTime().toString();returnQVariant();}
4. 设置标题栏
要显示标题栏,只需要重新实现模型(model)的headerData()函数
视图中可以通过tableView->verticalHeader()->hide()函数进行标题栏的显示与设置
QVariant MyModel::headerData(int section, Qt::Orientation orientation,int role)const{if(role == Qt::DisplayRole && orientation == Qt::Horizontal){switch(section){case0:returnQString("first");case1:returnQString("second");case2:returnQString("third");}}returnQVariant();}
5. 添加可编辑的视图
/ mymodel.h
#include<QAbstractTableModel>#include<QString>constint COLS=3;constint ROWS=2;classMyModel:publicQAbstractTableModel{
Q_OBJECT
public:MyModel(QObject *parent =nullptr);introwCount(const QModelIndex &parent =QModelIndex())constoverride;intcolumnCount(const QModelIndex &parent =QModelIndex())constoverride;
QVariant data(const QModelIndex &index,int role = Qt::DisplayRole)constoverride;boolsetData(const QModelIndex &index,const QVariant &value,int role = Qt::EditRole)override;//重新实现此函数,以实现对被编辑的单元格的操作
Qt::ItemFlags flags(const QModelIndex &index)constoverride;private:
QString m_gridData[ROWS][COLS];//holds text entered into QTableView
signals:voideditCompleted(const QString &);};
模型(model)中的
data()
函数直接将
m_gridData
中的数据显示到视图中
QVariant MyModel::data(const QModelIndex &index,int role)const{if(role == Qt::DisplayRole &&checkIndex(index))return m_gridData[index.row()][index.column()];returnQVariant();}
要实现对于视图中项的的可编辑性,需要重新实现模型(model)中的setData()函数。每当视图中的某个项被编辑时,都会调用setData()函数,其中,参数
index
告诉函数那个项被编辑了,
value
代表被编辑的内容,
role
代表操作角色。如果要想设置勾选框,则操作角色就为Qt::CheckStateRole.
boolMyModel::setData(const QModelIndex &index,const QVariant &value,int role){if(role == Qt::EditRole){if(!checkIndex(index))returnfalse;//将编辑的数据保存到m_gridData中
m_gridData[index.row()][index.column()]= value.toString();//用于演示,将编辑的数据保存到一个字符串中
QString result;for(int row =0; row < ROWS; row++){for(int col=0; col < COLS; col++)
result += m_gridData[row][col]+' ';}//输出结果
std::cout << result std::endl;returntrue;}returnfalse;}
Qt::ItemFlags MyModel::flags(const QModelIndex &index)const{return Qt::ItemIsEditable |QAbstractTableModel::flags(index);}
6. 获取鼠标选中的项
利用
QItemSelectionModel *selectionModel = tableView->selectionModel()
可以获取到视图中选中的项,其中
selectionModel
有一个信号
&QItemSelectionModel::selectionChanged
,即当被选中项发生改变时触发信号,利用该信号可以获取到所需要的选中项
//mainwindow.h#ifndefMAINWINDOW_H#defineMAINWINDOW_H#include<QMainWindow>#include<iostream>
QT_BEGIN_NAMESPACE
classQTableView;//forward declarationclassQItemSelection;
QT_END_NAMESPACE
classMainWindow:publicQMainWindow{
Q_OBJECT
private:
QTableView *tableView;public:MainWindow(QWidget *parent =nullptr);public slots:voidshowWindowTitle(const QString &title);private slots:voidselectionChangedSlot(const QItemSelection &newSelection,const QItemSelection &oldSelection);};#endif// MAINWINDOW_H
//mainwindow.cpp#include"mainwindow.h"#include"mymodel.h"#include<QTableView>MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),tableView(newQTableView(this)){setCentralWidget(tableView);
MyModel *myModel =newMyModel(this);
tableView->setModel(myModel);//将项的编辑完成信号与处理函数进行绑定connect(myModel,&MyModel::editCompleted,this,&MainWindow::showWindowTitle);//将项的选中焦点变化与处理函数进行绑定
QItemSelectionModel *selectionModel = tableView->selectionModel();//选中对象connect(selectionModel,&QItemSelectionModel::selectionChanged,this,&MainWindow::selectionChangedSlot);}voidMainWindow::showWindowTitle(const QString &title){setWindowTitle(title);}voidMainWindow::selectionChangedSlot(const QItemSelection &/*newSelection*/,const QItemSelection &/*oldSelection*/){//获取选中项中的内容const QModelIndex index = tableView->selectionModel()->currentIndex();
QString selectedText = index.data(Qt::DisplayRole).toString();//打印选中项的位置和内容
QString showString =QString("%1, %2, %3").arg(index.row()).arg(index.column()).arg(selectedText);
std::cout << showString.toStdString()<< std::endl;}
// mymodel.h#include<QAbstractTableModel>#include<QString>constint COLS=3;constint ROWS=2;classMyModel:publicQAbstractTableModel{
Q_OBJECT
public:MyModel(QObject *parent =nullptr);introwCount(const QModelIndex &parent =QModelIndex())constoverride;intcolumnCount(const QModelIndex &parent =QModelIndex())constoverride;
QVariant data(const QModelIndex &index,int role = Qt::DisplayRole)constoverride;boolsetData(const QModelIndex &index,const QVariant &value,int role = Qt::EditRole)override;//重新实现此函数,以实现对被编辑的单元格的操作
Qt::ItemFlags flags(const QModelIndex &index)constoverride;private:
QString m_gridData[ROWS][COLS];//holds text entered into QTableView
signals:voideditCompleted(const QString &);};
//mymodel.cpp#include"mymodel.h"MyModel::MyModel(QObject *parent):QAbstractTableModel(parent){}intMyModel::rowCount(const QModelIndex &/*parent*/)const{return ROWS;}intMyModel::columnCount(const QModelIndex &/*parent*/)const{return COLS;}
QVariant MyModel::data(const QModelIndex &index,int role)const{if(role == Qt::DisplayRole &&checkIndex(index))return m_gridData[index.row()][index.column()];returnQVariant();}boolMyModel::setData(const QModelIndex &index,const QVariant &value,int role){if(role == Qt::EditRole){if(!checkIndex(index))returnfalse;//将数据保存到m_gridData
m_gridData[index.row()][index.column()]= value.toString();//将所有项中的内容添加到result中
QString result;for(int row =0; row < ROWS; row++){for(int col=0; col < COLS; col++)
result += m_gridData[row][col]+' ';}
emit editCompleted(result);returntrue;}returnfalse;}
Qt::ItemFlags MyModel::flags(const QModelIndex &index)const{return Qt::ItemIsEditable |QAbstractTableModel::flags(index);}
版权归原作者 AoDeLuo 所有, 如有侵权,请联系我们删除。