Qt6.0开发 第五章 模型-视图结构
第五章 模型-视图结构
模型-视图结构概述
模型-视图结构是一种将数据存储和界面分离的编程方法.模型存储数据,视图组件显示模型中的数据,在视图组件里修改的数据会被自动保存到模型里.
GUI程序的主要功能是可由用户在界面上编辑和修改数据,典型的如数据库应用程序.在数据库应用程序中,界面上的数据来源于数据库,用户在界面上修改数据,修改后的数据又保存到数据库.
模型-视图的基本结构包括以下几个部分:
- 源数据(data):原始数据,如数据库的一个数据表或SQL查询结果等
- 视图(view):也称视图组件,是界面组件,视图从模型获得数据然后将其显示在界面上.
- 模型(model):也称数据模型,与源数据通信,并为视图组件提供数据接口.它从源数据提取需要的数据,用于视图组件进行显示和编辑.
- 代理(delegate):为视图与模型之间交互操作提供临时的编辑器.模型向视图提供数据一般是单向的,一般仅用于显示.当需要在视图上编辑数据时,代理会为编辑数据提供一个编辑器.
模型
所有基于项(item)的模型类都是基于QAbstractItemModel类的,这个类定义了试图组件和代理存取数据的接口.
模型只是在内存中临时存储数据,模型的数据来源可以是其他类,文件,数据库或任何数据源.
模型类继承关系:
- QAbstractItemModel:抽象模型类父类
- QFileSystemModel:用于表示计算机上文件系统的模型类
- QAbstractListModel:抽象列表类
- QStringListModel:用于表示字符串列表数据的模型类
- QStandardItemModel:标准的基于项的模型类,每个项都为QStandardItem对象
- QAbstractTableModel:抽象表类
- QSqlQueryModel:用于表示数据库SQL查询结果的模型类
- QSqlTableModel:用于表示数据库的一个数据表的模型类
- QSqlQueryModel:用于表示数据库SQL查询结果的模型类
视图
视图就是用于显示模型中的数据的界面组件,Qt提供的视图组件主要有以下几个:
- QListView:用于显示单列的列表结构,适用于一维数据
- QTreeView:用于显示树状结构的数据,适用于树状结构数据的操作
- QTableView:用于显示表格数据,适用于二维表格数据的操作
- QColumnView:用多个QListView显示树状结构数据,树状结构的一层用一个QListView显示
- QUndoView:用于显示undo指令栈内数据的视图组件,是QListView的子类
只需调用视图类的setModel()函数为视图组件设置一个模型,模型的数据就可以显示在视图组件上.在视图组件上修改数据后,数据可以自动保存到模型.
视图组件的数据来源于模型,视图组件不存储数据.便利类则为组件的每个节点或单元格创建一个项,用项存储数据.
因此,便利类缺乏对大型数据源进行灵活处理的能力,只适用于小型数据的显示和编辑,而视图组件则会根据模型的数据内容自动显示.
代理
代理能够在视图组件上为编辑数据提供临时的编辑器.代理负责从模型获取相应的数据,然后将其显示在编辑器里,修改数据又将编辑器里的数据保存到模型中.
QAbstractItemDelegate是所有代理类的基类,作为抽象类,它不能直接用于创建对象.它有两个子类,即QItemDelegate和QStyledItemDelegate,这两个类基本相同,而QStyledItemDelegate能使用Qt样式表定义的当前样式绘制代理组件.
对于一些特殊的数据编辑需求,则可以从QStyledItemDelegate中继承.
一些基本概念
在模型-视图结构中,模型为视图组件和代理提供存取数据的标准接口.
QAbstractItemModel是所有模型类的基类,不管底层的数据结构是如何组织数据的,QAbstractItemModel的子类都以表格的层次结构展示数据,视图组件按照这种规则规则来存取模型中的数据,但是展示给用户的形式不一样.
模型的三种常见展示形式:
- 列表模型(list model)
- 表格模型(table model)
- 树状模型(tree model)
不管模型的表现形式是怎样的,模型中存储数据的基本单元都是项(item),每个项有一个行号和一个列号,还有一个父项(parent item).三个模型都有一个隐藏的根项(item).
为了确保数据的展示与数据存取方式分离,模型中引入了模型索引(model index)的概念.通过模型索引,视图组件和代理都通过模型索引来获取数据.
QModelIndex是表示模型索引的类.模型索引提供访问数据的临时指针,用于通过模型提取或修改数据.
因为模型内部组织数据的结构可能随时改变,所以模型索引是临时的.
模型的基本形式是用行和列定义的表格数据,但这并不意味着底层的数据是用二维数据存储的,是用行与列只是为了组件之间交互方便.一个模型索引包含行号与列号.
在创建模型索引的函数中需要传递行号,列号和父项的模型索引.
当模型为列表或表格结构时,是用行号、列号访问数据比较直观,所有项的父项就是顶层项.
当模型为树状结构时情况比较复杂,一个节点有父节点,其他可以是其他节点的父节点,在构造节点的模型索引时,需要指定正确的行号,列号和父节点.
在为模型的一个项设置数据时,可以为项设置不同的角色数据.QAbstractItemModel定义了设置项的数据的函数setData():
- bool QAbstractItemModel:::setData(const QModelIndex& index,const
QVariant &value,int role =Qt::EditRole)
其中,index是项的模型索引,value是需要设置的数据,role是设置数据的角色.
可以为一个项设置不同角色的数据,角色参数role用枚举类型Qt::ItemDataRole的枚举类型表示.枚举类型Qt::ItemDataRole常用的一些枚举值及其含义如表所示,表中的橘色数据类型用于相应数据的数据的类型:
- bool QAbstractItemModel::setData(const QModelIndex &index,const QVariant &value,int role=Qt::EditRole)
枚举值 | 角色数据类型 | 含义 |
---|---|---|
Qt::DisplayRole | QString | 界面上显示的字符串 |
Qt::DecorationRole | QIcon,QColor | 在界面上期装饰作用的数据 |
Qt::EditRole | QString | 界面上适合在编辑器中显示的数据 |
Qt::ToolTipRole | QString | 项的toolTip |
Qt::StatusTipRole | QString | 项的statusTip |
Qt::FontRole | QFont | 项的字体 |
Qt::TextAlignmentRole | Qt::Alignment | 项的对齐方式 |
Qt::BackgroundRole | QBrush | 项的背景色 |
Qt::ForegroundRole | QBrush | 项的前景色 |
Qt::CheckStateRole | Qt::CheckState | 项的复选状态 |
Qt::UserRole | QVariant | 自定义的用户数据 |
在获取一个项的数据时也需要指定角色,以获取不同角色的数据.QAbstractItemModel定义了函数data()可以返回一个项的不同角色的数据.
- QVariant QAbstractItemModel::data(const QModelIndex &index,int role=Qt::DisplayRole)
通过为一个项的不同角色定义数据,可以告知试图组件和代理如何展示数据.
QAbstractItemModel类
QAbstractItemModel是所有模型类的字节或间接父类,它定义了模型的通用接口函数,作为抽象类不能直接用来创建对象实例.
由于QAbstractItemModel是抽象类,所以它的很多函数都是虚函数.
下面给出一些关于QAbstractItemModel的接口函数:
- int rowCount(const QModelIndex &parent=QModelIndex())//返回行数
- int columnCount(const QModelIndex &parent=QModelIndex())//返回列数
- bool insertRow(int row,const QModelIndex &parent=QModelIndex())//插入行
- bool insertRows(int row,int count,const QModelIndex &parent=QModelIndex())//插入多行
- bool removeRow(int row,const QModelIndex &parent=QModelIndex())//移除行
- bool removeRows(int row,int count,const QModelIndex &parent=QModelIndex())//移除多行
- bool insertColumn(int column,const QModelIndex &parent=QModelIndex())//插入列
- bool insertColumns(int column,int count,const QModelIndex &parent=QModelIndex())//插入多列
- bool removeColumn(int column,const QModelIndex &parent=QModelIndex())//移除列
- bool removeColumns(int column,int count,const QModelIndex &parent=QModelIndex())//移除多列
- bool moveRow(const QModelIndex &sourceParent,int sourceRow,const QModelIndex &destinationParent,int destinationChild)//移动行
- bool moveColumn(const QModelIndex &sourceParent,int sourceColumn,const QModelIndex &destinationParent,int destinationChild)//移动列
- void sort(int column,Qt::SortOrder order=Qt::AscendingOrder)//排序项
- bool setData(const QModelIndex &index,const QVariant &value,int role=Qt::EditRole)//设置数据
- QVariant data(const QModelIndex &index,int role=Qt::EditRole)//返回数据
- bool clearItemData(const QModelIndex &index)//清楚项的数据
QAbstractItemView类
QAbstractView类是所有视图组件类的父类,它定义了视图组件类共有的一些接口.
下面是其常用的一些函数:
- void setModel(QAbstractItemModel *model)//设置数据模型
- QAbstractItemModel *model()//返回关联模型的数据对象指针
- void setSelectionModel(QItemSelectionModel *selectionModel)//设置选择模型
- QItemSelectionModel *selectionModel()//返回选择模型的对象指针
- QModelIndex currentIndex()//返回当前项的模型索引
- void setCurrentIndex(const QModelIndex &index)//设置模型索引为index的项为当前项
- void selectAll()//选择视图中的所有项
- void clearSelection()//清除所有选择
下面是一些常用的属性:
- editTriggers属性:表示视图组件是否可以编辑数据以及进入编辑状态的方式等.
- 常用函数有:
- void setEditTriggers(QAbstractItemView::EditTriggers triggers)//
- QAbstractItemView::EditTriggers editTriggers()
- QAbstractItemView::EditTriggers的值有:
- NoEditTriggers:不允许编辑
- CurrentChanged:当前项变化时进入编辑状态
- DoubleClicked:点击一个已选择的项时进入编辑状态
- SelectedClicked:点击一个已选择的项时进入编辑状态
- EditKeyPressed:当平台的编辑按键被按下时进入编辑状态
- AnyKeyPressed:任何键被按下时进入编辑状态
- AllEditTriggers:发生以上任何动作时进入编辑状态
- 常用函数有:
- alternatingRowColors属性:这个属性设置各行是否需要交替使用不同背景色.
- selectionMode属性:这个属性表示在视图组件上选择项的操作模式,该属性值一般为SelectionMode类型
- QAbstractItemView::SelectionMode的值有:
- SingleSelection:单选
- ContiguousSelection:连续选择,如按住shift
- ExtendedSelection:扩展选择,如按住ctrl
- MultiSelection:多选
- NoSelection:不允许选择
- QAbstractItemView::SelectionMode的值有:
- selectionBehavior属性:这个属性表示点击鼠标时操作的行为,属性值为SelectionBehavior类型.
- QAbstractItemView::SelectionBehavior的值有:
- SelectItems:选择单个项
- SelectRows:选择行,点击单个单元格选择对应行
- SelectColumns:选择列,点击单个单元格选择对应列
- QAbstractItemView::SelectionBehavior的值有:
QAbstractItemView常用的信号有:
- void clicked(const QModelIndex &index)//点击某个项时
- void doubleClicked(const QModelIndex &index)//双击某个项时
- void entered(const QModelIndex &index)//鼠标移动到某个项时
- void pressed(const QModelIndex &index)//鼠标单击某个项时
QStringListModel和QListView
QStringListModel是处理字符串列表的模型类,其实例可以作为QListView组件的数据模型.
QStringListModel内部存储了一个字符串列表,通过字符串列表内容自动显示在关联容器上.
QStringListModel类
QStringListModel类有两种参数形式的构造函数,定义如下:
- QStringListModel(const QStringList&strings,QObject *parent=nullptr)
- QStringListModel(QObject *parent=nullptr)
作为字符串列表数据的模型,QStringListModel对象内部有一个字符串列表,对模型数据的修改就是对QStringListModel对象内部字符串的修改.
QStringListModel继承于QAbstractItemModel,新增加的函数只有两个:
- void setStringList(const QStringList &strings)//设置字符串列表
- QStringList stringList()//返回模型内部的字符串列表
下面给出一个使用例子用于方便理解:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_list<<"北京"<<"上海"<<"成都"<<"长沙"<<"广州";
m_lisModel= new QStringListModel(m_list,this);
m_lisModel->setStringList(m_list);
ui->ltvView1->setModel(m_lisModel);
ui->ltvView1->setEditTriggers(QAbstractItemView::DoubleClicked|
QAbstractItemView::SelectedClicked);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnReliveList_clicked()
{
m_lisModel->setStringList(m_list);
}
void MainWindow::on_btnClearList_clicked()
{
m_lisModel->removeRows(0,m_lisModel->rowCount());
}
void MainWindow::on_chkEditable_clicked(bool checked)
{
if(checked)
ui->ltvView1->setEditTriggers(QAbstractItemView::DoubleClicked|
QAbstractItemView::SelectedClicked);
else
ui->ltvView1->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
void MainWindow::on_btnAddItem_clicked()
{
m_lisModel->insertRow(m_lisModel->rowCount());
QModelIndex index= m_lisModel->index(m_lisModel->rowCount()-1);
m_lisModel->setData(index,QString("new item %1").arg(m_lisModel->rowCount()),Qt::DisplayRole);
ui->ltvView1->setCurrentIndex(index);
}
void MainWindow::on_btnInsertItem_clicked()
{
QModelIndex index= ui->ltvView1->currentIndex();
m_lisModel->insertRow(index.row());
m_lisModel->setData(index,QString("new item %1").arg(index.row()),Qt::DisplayRole);
ui->ltvView1->setCurrentIndex(index);
}
void MainWindow::on_btnDeleteItem_clicked()
{
QModelIndex index= ui->ltvView1->currentIndex();
m_lisModel->removeRow(index.row());
}
void MainWindow::on_btnUpper_clicked()
{
QModelIndex index;
int curRow= ui->ltvView1->currentIndex().row();
m_lisModel->moveRow(index,curRow,index,curRow-1);
}
void MainWindow::on_btnLower_clicked()
{
QModelIndex index;
int curRow= ui->ltvView1->currentIndex().row();
m_lisModel->moveRow(index,curRow,index,curRow+2);
}
void MainWindow::on_btnSort_clicked(bool checked)
{
if(checked)
m_lisModel->sort(Qt::AscendingOrder);
else
m_lisModel->sort(Qt::DescendingOrder);
}
void MainWindow::on_btnClearPlt_clicked()
{
ui->pltEdit->clear();
}
void MainWindow::on_btnShowSL_clicked()
{
QStringList tempList= m_lisModel->stringList();
ui->pltEdit->clear();
for(auto iter:tempList)
ui->pltEdit->appendPlainText(iter);
}
QStanardItemModel和QTableView
QStandardItemModel是基于项的模型类,每个项是一个QStandardItem对象,可以存储各种数据.QStandardItemModel通常与QTableView组成模型-视图结构,实现二维数据的管理.
QTableView类
QTableView继承自QAbstractItemView类,其新定义的属性主要用于控制显示效果,在UI可视化设计时就可以设置QTableView组件的各种属性.
QTableView组件有水平表头和垂直表头,都是QHeaderView对象,可以设置和返回表头对象.
相关函数定义如下:
- void QTableView::setHorizontalHeader(QHeaderView *header)//设置水平表头
- void QTableView::setVerticalHeader(QHeaderView *header)//设置垂直表头
- QHeaderView *QTableView::horizontalHeader()//返回水平表头对象指针
- QHeaderView *QTableView::verticalHeaer()//返回垂直表头对象指针
当QTableView使用一个QStandardItemModel对象作为数据模型时,它会自动创建表头对象,垂直表头一般显示行号,水平表头一般显示列的标题.
QStandardItemModel类
QStandardItemModel是以项为基本数据单元的模型类,每个项是一个QStandardItem对象.
项可以存储各种角色的数据,如文字,字体,对齐方式,图标,复选状态等.
如果以多行多列的二维数组形式存储项,就是表格模型;如果表格模型只有一列,就是列表模型;如果存储项时为项指定父项,就构成树状模型.
如果一个QStandardItemModel对象是表格模型,将它设置为QTableView组件的数据模型后,视图组件就用表格的形式显示模型的数据,并且根据每个单元格的项定义各种角色数据控制显示效果.
QStandardItemModel的接口主要有:
- void setRowCount(int rows)
- void setColumnCount(int columns)
- void setItem(int row,int column,QStandardItem *item)
- void setItem(int row,QStandardItem *item)
- QStandardItem *item(int row,int column=0)
- QStandardItem *itemFromIndex(const QModelIndex &index)
- QModelIndex indexFromItem(const QStandardItem *item)
- void appendRow(const QList<QStandardItem *>&items)
- void appendRow(QStandardItem *item)
- void appednColumn(cosnt QList<QStandardItem*>&items)
- void insertRow(int row,const QList<QStandardItem *>&items)
- void insertRow(int row,QStandardItem *item)
- bool insertRow(int row,const QModelIndex &parent=QModelIndex())
- void insertColumn(int column,const QList<QStandardItem *>&items)
- bool insertColumn(int column,const QModelIndex &parent=QModelIndex())
- QList<QStandardItem*>takeRow(int row)
- QList<QStandardItem*>takeColumn(int column)
- QStandardItem *takeItem(int row,int column=0)
- void setHorizontalHeaderItem(int column,QStandardItem *item)
- void setHorizontalHeaderLabels(const QStringList &labels)
- QStandardItem *horizontalHeaderItem(int column)
- QStandardItem takeHorizontalHeaderItem(int column)
- void setVerticalHeaderItem(int row,QStandardItem *item)
- void setVerticalHeaderLabels(const QStringList &labels)
- QStandardItem *verticalHeaderItem(int row)
- QStandardItem *takeVerticalHeaderItem(int row)
- void clear()
QStandardItemModel新定义了一个信号,在任何一个项的数据变化时该信号就会发射:
- void itemChanged(QStandardItem *item)
QStandardItem类
QStandardItemModel数据模型中每个项都是一个QStandardItem对象.QStandardItem对象存储了一个项的各种特性参数,还可以存储用户自定义数据.一个项可以添加子项,子项也是QStandardItem类型的对象.
QStandardItem类没有父类,它存储项的各种特性内容与设置各种特性.
读取函数 | 设置函数 | 设置函数的功能 |
---|---|---|
text() | setText() | 设置项的显示文字 |
toolTip() | setToolTip() | 设置toolTip文字 |
statusTip() | setStatusTip() | 设置statusTip文字 |
icon() | setIcon() | 设置项的图标 |
font() | setFont() | 设置文字的字体 |
textAlignment() | setTextAlignment() | 设置文字的对齐方式 |
foreground() | setForeground() | 设置项的前景色 |
background() | setBackground() | 设置项的背景色 |
isEnabled() | setEnabled() | 设置项是否能够交互 |
isEditable() | setEditable() | 设置项是否可以被编辑 |
isSelectable() | setSelectable() | 设置项是否可以被选择 |
isCheckable() | setCheckable() | 设置项是否可以复选 |
checkState() | setCheckable() | 设置项的复选状态 |
isAutoTristate() | setAutoTristate() | 设置是否自动改变三种复选状态 |
isUserTristate() | setUserTristate() | 设置是否由用户决定三种复选状态 |
flags() | setFlags() | 设置项的标志 |
row() | -- | 返回自身父项的所有子项的行号 |
column() | -- | 返回自身父项的所有子项的列号 |
此外,还有一些函数很重要:
- void QStandardItem::setFlags(Qt::ItemFlags flags)//设置标志
- void QStandardItem::setData(const QVariant &value,int role=Qt::UserRole+1)//设置自定义数据
- QVariant QStandardItem::data(int role=Qt::UserRole+1)//返回用户自定义数据
- void QStandardItem::clearData()//清除用户自定义数据
QStandard管理子项的函数有:
- void appendRow(const QList<QStandardItem *>&items)
- void appendRow(QStandardItem *item)
- void appednColumn(cosnt QList<QStandardItem*>&items)
- void insertRow(int row,const QList<QStandardItem *>&items)
- void insertRow(int row,QStandardItem *item)
- bool insertRow(int row,const QModelIndex &parent=QModelIndex())
- void insertColumn(int column,const QList<QStandardItem*>&items)
- void insertColumns(int column,int count)
- void removeColumn(int column)
- void removeColumns(int column,int count)
- int rowCount()
- int columnCount()
- bool hasChildren()
- QStandardItem *child(int row,int column=0)
如果采用树状模型,那么QStandardItemModel管理所有的顶层项,而各个一级节点的字节子节点则通过QStandardItem类来管理.
QItemSelectionModel类
一个视图组件需要设置一个数据模型,还可以设置一个选择模型.QItemSelectionModel是选择模型类,它的功能是跟踪视图组件上的选择操作,给出选择范围.
为了设置视图模型,需要用到函数setModell()为模型设置数据模型,函数定义如下:
- void QItemSelecitonModel::setModel(QAbstractItemModel *model)//为选择模型设置数据模型
将数据模型,选择模型,视图模型这3种对象做好关联设置后,在视图组件上进行选择操作时,选择模型就可以跟踪视图组件上的选择操作.
QItemSelectionModel有一些接口函数:
- bool hasSelection()//是否有被选择的项
- QModelIndex currentIndex()//返回当前项的模型索引
- bool isSelected(const QModelIndex &index)//模型索引为index的项是否被选中
- QModelIndexList selectedIndexes()//返回所有被选择项的模型索引列表
- QModelIndexList selectedRows(int column=0)//返回column列所有被选择项的模型索引列表
- QModelIndexList selectedColumns(int row=0)//返回row行所有被选择项的模型索引表
- void clear()//清除选择模型
- void clearCurrentIndex()//清除当前索引
- void clearSelection()//清除所有选择
QItemSelectionModel有几个信号:
- void currentChanged(const QModelIndex ¤t,const QModelIndex &previous)//当前项改变
- void selectionChanged(const QItemSelection &selected,const QItemSelection &deselected)
//选择多个单元格或取消选择一些单元格
下面给出一个综合使用上述知识的例子:
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QString>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QLabel *labCurFile,*labCellPos,*labCellText;
const int fixedColum=6;
QStandardItemModel *m_model;
QItemSelectionModel *m_selection;
void iniModelData(QStringList &fileContent);
private slots:
void do_currentChanged(const QModelIndex¤t,const QModelIndex&previous);
void on_actOpen_triggered();
void on_actAddRow_triggered();
void on_actInsertRow_triggered();
void on_actDeleteRow_triggered();
void on_actModelData_triggered();
void on_actAlignLeft_triggered();
void on_actAlignCenter_triggered();
void on_actAlignRight_triggered();
void on_actFontBold_triggered(bool checked);
};
#endif // MAINWINDOW_H
mainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
labCurFile=new QLabel("当前文件",this);
labCurFile->setMinimumWidth(200);
labCellPos=new QLabel("当前单元格",this);
labCellPos->setMinimumWidth(200);
labCellText=new QLabel("单元格内容",this);
labCellText->setMinimumWidth(200);
ui->statusbar->addWidget(labCurFile);
ui->statusbar->addWidget(labCellPos);
ui->statusbar->addWidget(labCellText);
m_model= new QStandardItemModel(2,fixedColum,this);
m_selection= new QItemSelectionModel(m_model,this);
ui->tableView->setModel(m_model);
ui->tableView->setSelectionModel(m_selection);
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
connect(m_selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(do_currentChanged(QModelIndex,QModelIndex)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::iniModelData(QStringList &fileContent)
{
int rowCount=fileContent.size();
m_model->setRowCount(rowCount-1);
QString header=fileContent.at(0);
QStringList headerList=header.split(QRegularExpression(R"(\s+)"),Qt::SkipEmptyParts);
m_model->setHorizontalHeaderLabels(headerList);
for(int i=1;i<rowCount;i++){
QString lineText=fileContent.at(i);
QStringList tempList=lineText.split(QRegularExpression(R"(\s+)"),Qt::SkipEmptyParts);
QStandardItem *item= new QStandardItem(tempList.at(0));
item->setCheckable(true);
item->setBackground(QBrush(Qt::yellow));
if(tempList.at(0)=="0")
item->setCheckState(Qt::Unchecked);
else
item->setCheckState(Qt::Checked);
m_model->setItem(i-1,0,item);
for(int j=1;j<=5;j++){
item=new QStandardItem(tempList.at(j));
m_model->setItem(i-1,j,item);
}
}
}
void MainWindow::do_currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
if(current.isValid()){
labCellPos->setText(QString::asprintf("当前单元格:%d行,%d列",current.row(),current.column()));
QStandardItem *tempItem= m_model->itemFromIndex(current);
labCellText->setText(QString("单元格内容:%1").arg(tempItem->text()));
ui->actFontBold->setChecked(tempItem->font().bold());
}
}
void MainWindow::on_actOpen_triggered()
{
QString curPath= QCoreApplication::applicationDirPath();
QString fileName= QFileDialog::getOpenFileName(this,"打开一个文件",curPath,"数据文件(*.txt);所有文件(*.*)");
if(fileName.isEmpty())
return;
QFile fileObject(fileName);
if(!fileObject.open(QIODevice::ReadOnly|QIODevice::Text))
return;
QStringList fileContent;
ui->plainTextEdit->clear();
QTextStream tempStream(&fileObject);
while(!tempStream.atEnd()){
QString str=tempStream.readLine();
ui->plainTextEdit->appendPlainText(str);
fileContent.append(str);
}
fileObject.close();
labCurFile->setText("当前文件:"+fileName);
ui->actAddRow->setEnabled(true);
ui->actInsertRow->setEnabled(true);
ui->actDeleteRow->setEnabled(true);
iniModelData(fileContent);
}
void MainWindow::on_actAddRow_triggered()
{
QList<QStandardItem*>itemList;
QString str=m_model->headerData(0,Qt::Horizontal).toString()+QString::number(m_model->rowCount());
QStandardItem *item=new QStandardItem(str);
item->setColumnCount(6);
item->setCheckable(true);
item->setCheckState(Qt::Checked);
item->setBackground(Qt::yellow);
itemList<<item;
for(int i=0;i<m_model->columnCount()-1;i++){
item=new QStandardItem("0");
itemList<<item;
}
m_model->appendRow(itemList);
m_selection->clearSelection();
m_selection->setCurrentIndex(m_model->index(m_model->rowCount()-1,0),QItemSelectionModel::Select);
}
void MainWindow::on_actInsertRow_triggered()
{
QModelIndex index= ui->tableView->currentIndex();
QList<QStandardItem*>itemList;
QString str=m_model->headerData(0,Qt::Horizontal).toString()+QString::number(m_model->rowCount());
QStandardItem *item=new QStandardItem(str);
item->setColumnCount(6);
item->setCheckable(true);
item->setCheckState(Qt::Checked);
item->setBackground(Qt::yellow);
itemList<<item;
for(int i=0;i<m_model->columnCount()-1;i++){
item=new QStandardItem("0");
itemList<<item;
}
m_model->insertRow(index.row(),itemList);
m_selection->clearSelection();
m_selection->setCurrentIndex(m_model->index(index.row(),0),QItemSelectionModel::Select);
}
void MainWindow::on_actDeleteRow_triggered()
{
QModelIndex index= ui->tableView->currentIndex();
m_model->removeRow(index.row());
}
void MainWindow::on_actModelData_triggered()
{
ui->plainTextEdit->clear();
QStandardItem *item;
QString str="";
for(int i=0;i<m_model->columnCount();i++){
item=m_model->horizontalHeaderItem(i);
str+=item->text();
str+='\t';
}
ui->plainTextEdit->appendPlainText(str);
for(int i=0;i<m_model->rowCount();i++){
str.clear();
item=m_model->item(i,0);
if(item->checkState()==Qt::Checked)
str+="是 ";
else
str+="否 ";
for(int j=0;j<m_model->columnCount();j++){
item=m_model->item(i,j);
str+=item->text();
str+='\t';
}
ui->plainTextEdit->appendPlainText(str);
}
}
void MainWindow::on_actAlignLeft_triggered()
{
QStandardItem *item;
QModelIndexList indexList;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
item->setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
m_model->setItem(index.row(),index.column(),item);
}
}
void MainWindow::on_actAlignCenter_triggered()
{
QStandardItem *item;
QModelIndexList indexList;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
m_model->setItem(index.row(),index.column(),item);
}
}
void MainWindow::on_actAlignRight_triggered()
{
QStandardItem *item;
QModelIndexList indexList;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
m_model->setItem(index.row(),index.column(),item);
}
}
void MainWindow::on_actFontBold_triggered(bool checked)
{
QStandardItem *item;
QModelIndexList indexList;
QFont font;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
font=item->font();
font.setBold(checked);
item->setFont(font);
m_model->setItem(index.row(),index.column(),item);
}
}
自定义代理
在模型-视图结构中,代理的作用就是在视图组件进入编辑状态编辑某个项时,提供一个临时的编辑器用于数据编辑,编辑完成后再把数据提交给数据模型.
QTableView等视图组件的代理默认提供QLineEdit编辑框,在这个编辑框里可以输入任何数据,所以比较通用.
但是某些情况,我们也希望根据数据类型不同使用不同的编辑器,若要使用这样的功能,就需要使用自定义代理.
若要替换QTableView组件提供的默认代理组件,就需要为QTableView组件的某列或某个单元格设置自定义代理.
自定义代理类需要从QStyledItemDelegate类继承,创建自定义代理类的实例后,再将其设置为整个视图组件或视图组件的某行或某列的代理.
QAbstractItemView类定义了设置自定义代理的3个函数,定义如下:
- void setItemDelegate(QAbstractItemDelegate*delegate)
- void setItemDelegateForColumn(int column,QAbstractItemDelegate*delegate)
- void setItemDelegateForRow(int row,QAbstractItemDelegate*delegate)
其中,delegate是创建的自定义代理类的实例对象.
QStyledItemDelegate是视图组件使用的默认代理类,自定义代理类需要从QStyledItemDelegate类继承.
要自定义一个代理类,必须重新实现QStyledItemDelegate中定义的4个虚函数.
- QWidget*QStyledItemDelegate::createEditor(QWidget*parent,const QStyleOptionViewItem &option,const QModelIndex &index)//用于创建代理编辑器
- void QStyledItemDelegate::setEditorData(QWidget *editor,const QModelIndex &index)
//用于从数据模型获取项的某个角色(一般为EditRole),然后将其设置为代理编辑器上显示的数据 - void QStyledItemDelegate::setModelData(QWidget*editor,QAbstractItemModel *model,const QModelIndex &index)//完成对当前单元格的编辑
- void QStyledItemDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex &index)//为临时组件设置合适的大小
下面提供一个使用自定义代理的例子,改编自上面QStandardItemModel综合使用例子:
tcombobox_delegate.h
#ifndef TCOMBOBOXDELEGATE_H
#define TCOMBOBOXDELEGATE_H
#include <QObject>
#include <QStyledItemDelegate>
#include <QComboBox>
class TComboBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit TComboBoxDelegate(QObject *parent = nullptr);
// QAbstractItemDelegate interface
public:
void setItems(QStringList items,bool editable);
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
private:
QStringList m_itemList;
bool m_editable;
};
#endif // TCOMBOBOXDELEGATE_H
tfloat_spinbox_delegate.h
#ifndef TFLOATSPINBOXDELEGATE_H
#define TFLOATSPINBOXDELEGATE_H
#include <QObject>
#include <QStyledItemDelegate>
#include <QDoubleSpinBox>
class TFloatSpinBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit TFloatSpinBoxDelegate(QObject *parent = nullptr);
// QAbstractItemDelegate interface
public:
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
#endif // TFLOATSPINBOXDELEGATE_H
tspinbox_delegate.h
#ifndef TSPINBOXDELEGATE_H
#define TSPINBOXDELEGATE_H
#include <QObject>
#include <QSpinBox>
#include <QQmlEngine>
#include <QStyledItemDelegate>
class TSpinBoxDelegate : public QStyledItemDelegate
{
QML_ELEMENT
public:
explicit TSpinBoxDelegate(QObject *parent=nullptr);
// QAbstractItemDelegate interface
public:
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
#endif // TSPINBOXDELEGATE_H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QString>
#include <QStyledItemDelegate>
#include "tspinbox_delegate.h"
#include "tfloat_spinbox_delegate.h"
#include "tcombobox_delegate.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QLabel *labCurFile,*labCellPos,*labCellText;
const int fixedColum=6;
QStandardItemModel *m_model;
QItemSelectionModel *m_selection;
TSpinBoxDelegate* intSpinDelegate;
TFloatSpinBoxDelegate* doubleSpinDelegate;
TComboBoxDelegate* comboBoxDelegate;
void iniModelData(QStringList &fileContent);
private slots:
void do_currentChanged(const QModelIndex¤t,const QModelIndex&previous);
void on_actOpen_triggered();
void on_actAddRow_triggered();
void on_actInsertRow_triggered();
void on_actDeleteRow_triggered();
void on_actModelData_triggered();
void on_actAlignLeft_triggered();
void on_actAlignCenter_triggered();
void on_actAlignRight_triggered();
void on_actFontBold_triggered(bool checked);
};
#endif // MAINWINDOW_H
tcombobox_delegate.cpp
#include "tcombobox_delegate.h"
TComboBoxDelegate::TComboBoxDelegate(QObject *parent)
: QStyledItemDelegate{parent}
{
}
void TComboBoxDelegate::setItems(QStringList items, bool editable)
{
m_itemList=items;
m_editable=editable;
}
QWidget *TComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
QComboBox *editor=new QComboBox(parent);
editor->setEditable(m_editable);
for(auto iter:m_itemList)
editor->addItem(iter);
return editor;
}
void TComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QComboBox *comboBox=dynamic_cast<QComboBox*>(editor);
QString str=index.model()->data(index,Qt::EditRole).toString();
comboBox->setCurrentText(str);
}
void TComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *comboBox=dynamic_cast<QComboBox*>(editor);
QString str=comboBox->currentText();
model->setData(index,str,Qt::EditRole);
}
void TComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
tfloat_spinbox_delegate.cpp
#include "tfloat_spinbox_delegate.h"
TFloatSpinBoxDelegate::TFloatSpinBoxDelegate(QObject *parent)
: QStyledItemDelegate{parent}
{
}
QWidget *TFloatSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
QDoubleSpinBox *editor=new QDoubleSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(50000);
return editor;
}
void TFloatSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QDoubleSpinBox *spinBox=dynamic_cast<QDoubleSpinBox*>(editor);
double value=index.model()->data(index,Qt::EditRole).toDouble();
spinBox->setValue(value);
}
void TFloatSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QDoubleSpinBox *spinBox=dynamic_cast<QDoubleSpinBox*>(editor);
double value=spinBox->value();
model->setData(index,value);
}
void TFloatSpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
tspinbox_delegate.cpp
#include "tspinbox_delegate.h"
TSpinBoxDelegate::TSpinBoxDelegate(QObject *parent)
:QStyledItemDelegate(parent)
{
}
QWidget *TSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
QSpinBox *editor=new QSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(50000);
return editor;
}
void TSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QSpinBox *spinBox=dynamic_cast<QSpinBox*>(editor);
int value=index.model()->data(index,Qt::EditRole).toInt();
spinBox->setValue(value);
}
void TSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QSpinBox *spinBox=dynamic_cast<QSpinBox*>(editor);
int value=spinBox->value();
model->setData(index,value);
}
void TSpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
labCurFile=new QLabel("当前文件",this);
labCurFile->setMinimumWidth(200);
labCellPos=new QLabel("当前单元格",this);
labCellPos->setMinimumWidth(200);
labCellText=new QLabel("单元格内容",this);
labCellText->setMinimumWidth(200);
ui->statusbar->addWidget(labCurFile);
ui->statusbar->addWidget(labCellPos);
ui->statusbar->addWidget(labCellText);
m_model= new QStandardItemModel(2,fixedColum,this);
m_selection= new QItemSelectionModel(m_model,this);
ui->tableView->setModel(m_model);
ui->tableView->setSelectionModel(m_selection);
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
intSpinDelegate= new TSpinBoxDelegate;
ui->tableView->setItemDelegateForColumn(1,intSpinDelegate);
doubleSpinDelegate= new TFloatSpinBoxDelegate;
ui->tableView->setItemDelegateForColumn(3,doubleSpinDelegate);
ui->tableView->setItemDelegateForColumn(4,doubleSpinDelegate);
ui->tableView->setItemDelegateForColumn(5,doubleSpinDelegate);
comboBoxDelegate= new TComboBoxDelegate;
QStringList strList;
strList<<"名字1"<<"名字2"<<"名字3";
comboBoxDelegate->setItems(strList,true);
ui->tableView->setItemDelegateForColumn(0,comboBoxDelegate);
connect(m_selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(do_currentChanged(QModelIndex,QModelIndex)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::iniModelData(QStringList &fileContent)
{
int rowCount=fileContent.size();
m_model->setRowCount(rowCount-1);
QString header=fileContent.at(0);
QStringList headerList=header.split(QRegularExpression(R"(\s+)"),Qt::SkipEmptyParts);
m_model->setHorizontalHeaderLabels(headerList);
for(int i=1;i<rowCount;i++){
QString lineText=fileContent.at(i);
QStringList tempList=lineText.split(QRegularExpression(R"(\s+)"),Qt::SkipEmptyParts);
QStandardItem *item= new QStandardItem(tempList.at(0));
item->setCheckable(true);
item->setBackground(QBrush(Qt::yellow));
if(tempList.at(0)=="0")
item->setCheckState(Qt::Unchecked);
else
item->setCheckState(Qt::Checked);
m_model->setItem(i-1,0,item);
for(int j=1;j<=5;j++){
item=new QStandardItem(tempList.at(j));
m_model->setItem(i-1,j,item);
}
}
}
void MainWindow::do_currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
if(current.isValid()){
labCellPos->setText(QString::asprintf("当前单元格:%d行,%d列",current.row(),current.column()));
QStandardItem *tempItem= m_model->itemFromIndex(current);
labCellText->setText(QString("单元格内容:%1").arg(tempItem->text()));
ui->actFontBold->setChecked(tempItem->font().bold());
}
}
void MainWindow::on_actOpen_triggered()
{
QString curPath= QCoreApplication::applicationDirPath();
QString fileName= QFileDialog::getOpenFileName(this,"打开一个文件",curPath,"数据文件(*.txt);所有文件(*.*)");
if(fileName.isEmpty())
return;
QFile fileObject(fileName);
if(!fileObject.open(QIODevice::ReadOnly|QIODevice::Text))
return;
QStringList fileContent;
ui->plainTextEdit->clear();
QTextStream tempStream(&fileObject);
while(!tempStream.atEnd()){
QString str=tempStream.readLine();
ui->plainTextEdit->appendPlainText(str);
fileContent.append(str);
}
fileObject.close();
labCurFile->setText("当前文件:"+fileName);
ui->actAddRow->setEnabled(true);
ui->actInsertRow->setEnabled(true);
ui->actDeleteRow->setEnabled(true);
iniModelData(fileContent);
}
void MainWindow::on_actAddRow_triggered()
{
QList<QStandardItem*>itemList;
QString str=m_model->headerData(0,Qt::Horizontal).toString()+QString::number(m_model->rowCount());
QStandardItem *item=new QStandardItem(str);
item->setColumnCount(6);
item->setCheckable(true);
item->setCheckState(Qt::Checked);
item->setBackground(Qt::yellow);
itemList<<item;
for(int i=0;i<m_model->columnCount()-1;i++){
item=new QStandardItem("0");
itemList<<item;
}
m_model->appendRow(itemList);
m_selection->clearSelection();
m_selection->setCurrentIndex(m_model->index(m_model->rowCount()-1,0),QItemSelectionModel::Select);
}
void MainWindow::on_actInsertRow_triggered()
{
QModelIndex index= ui->tableView->currentIndex();
QList<QStandardItem*>itemList;
QString str=m_model->headerData(0,Qt::Horizontal).toString()+QString::number(m_model->rowCount());
QStandardItem *item=new QStandardItem(str);
item->setColumnCount(6);
item->setCheckable(true);
item->setCheckState(Qt::Checked);
item->setBackground(Qt::yellow);
itemList<<item;
for(int i=0;i<m_model->columnCount()-1;i++){
item=new QStandardItem("0");
itemList<<item;
}
m_model->insertRow(index.row(),itemList);
m_selection->clearSelection();
m_selection->setCurrentIndex(m_model->index(index.row(),0),QItemSelectionModel::Select);
}
void MainWindow::on_actDeleteRow_triggered()
{
QModelIndex index= ui->tableView->currentIndex();
m_model->removeRow(index.row());
}
void MainWindow::on_actModelData_triggered()
{
ui->plainTextEdit->clear();
QStandardItem *item;
QString str="";
for(int i=0;i<m_model->columnCount();i++){
item=m_model->horizontalHeaderItem(i);
str+=item->text();
str+='\t';
}
ui->plainTextEdit->appendPlainText(str);
for(int i=0;i<m_model->rowCount();i++){
str.clear();
item=m_model->item(i,0);
if(item->checkState()==Qt::Checked)
str+="是 ";
else
str+="否 ";
for(int j=0;j<m_model->columnCount();j++){
item=m_model->item(i,j);
str+=item->text();
str+='\t';
}
ui->plainTextEdit->appendPlainText(str);
}
}
void MainWindow::on_actAlignLeft_triggered()
{
QStandardItem *item;
QModelIndexList indexList;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
item->setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
m_model->setItem(index.row(),index.column(),item);
}
}
void MainWindow::on_actAlignCenter_triggered()
{
QStandardItem *item;
QModelIndexList indexList;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
m_model->setItem(index.row(),index.column(),item);
}
}
void MainWindow::on_actAlignRight_triggered()
{
QStandardItem *item;
QModelIndexList indexList;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
m_model->setItem(index.row(),index.column(),item);
}
}
void MainWindow::on_actFontBold_triggered(bool checked)
{
QStandardItem *item;
QModelIndexList indexList;
QFont font;
if(!m_selection->hasSelection())
return;
indexList=m_selection->selectedIndexes();
for(auto index:indexList){
item= m_model->item(index.row(),index.column());
font=item->font();
font.setBold(checked);
item->setFont(font);
m_model->setItem(index.row(),index.column(),item);
}
}
QFileSystemModel和QTreeView
QFileSystemModel为文件系统提供一个模型,综合使用QFileSystemModel和QTreeView可以以目录树的形式显示本机的文件系统,如同Windows的资源管理器一样.
QFileSystemModel类
要通过QFileSystemModel获得本机的文件系统,需要用QFileSystemModel的函数setRootPath()设置一个根目录.如果需要使用条件过滤,则还需要设置过滤器.
QFileSystemModel类的主要成员函数如下:
- QModelIndex setRootPath(const QString &newPath)//设置根目录
- QDir rootDirectory()//以QDir类返回目录
- QString rootPath()//以QString类返回目录
- QModelIndex index(const QString &path,int column=0)//返回目录或文件的模型索引
- void setFilter(QDir::Filters filters)//设置模型数据项过滤器
- void setNameFilters(const QStringList &filters)//设置文件名过滤器
- void setNameFilterDisables(bool enable)//设置文件名过滤器
- void setOption(QFileSystemModel::Option option,bool on=true)//设置模型选项
- QIcon fileIcon(const QModelIndex &index)//返回项的图标
- QFileInfo fileInfo(const QModelIndex &index)//返回项的文件信息
- QString fileName(const QModelIndex &index)//返回不含路径的文件名或最后一级文件夹名称
- QString filePath(const QModelIndex &index)//返回项的路径或包含路径的文件名
- QDateTime lastModified(const QModelIndex &index)//返回项的最后修改日期
- bool isDir(const QModelIndex &index)//判断项是不是一个文件夹
- qint64 size(const QModelIndex &index)//返回文件的大小字节数
- QString type(const QModelIndex &index)//返回项的类型描述文字
- QModelIndex mkdir(const QModelIndex &parent,const QString &name)//创建文件夹
- bool rmdir(const QModelIndex &index)//删除文件夹
- bool remove(const QModelIndex &index)//删除文件
相关的一些内容:
- QDir的枚举值:
- QDir::AllDirs:列出所有目录
- QDir::Files:列出文件
- QDir::Drives:列出驱动器
- QDir::NoDotAndDotDot:不列出目录下的'.'和'..'特殊项
- QDir::Hidden:列出隐藏的文件
- QDir::System:列出系统文件
- QFileSystemModel::Option的枚举值:
- QFileSystemModel::Option::DontWatchForChanges:不监视文件系统的变化
- QFileSystemModel::Option::DontResolveSymlinks:不解析文件系统的符号连接项
- QFileSystemModel::Option::DontUseCustomDirectoryIcons:不使用自定义的目录图标
QTreeView类
QTreeView类是用于显示树状模型的视图组件,其与QFileSystemModel模型结合就可以显示本机的文件系统.
如果QTreeView组件允许多选操作,就需要使用QItemSelectionModel选择模型.
关于文件系统有关内容,后面会进一步深入,因而暂时不用太过在意.
下面是一个综合使用的样例:
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include <QFileDialog>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_actSetRootDir_triggered();
void on_radOnlyDirAndFile_clicked();
void on_radOnlyDir_clicked();
void on_chkFliterFile_clicked(bool checked);
void on_btnApplicate_clicked();
void on_treeView_clicked(const QModelIndex &index);
private:
Ui::MainWindow *ui;
QFileSystemModel *m_model;
};
#endif // MAINWINDOW_H
mainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->radOnlyDirAndFile->setChecked(true);
m_model=new QFileSystemModel(this);
ui->treeView->setModel(m_model);
ui->listView->setModel(m_model);
ui->tableView->setModel(m_model);
m_model->setRootPath(QDir::currentPath());
//ui->treeView->setRootIndex(m_model->index(QDir::currentPath()));
connect(ui->treeView,SIGNAL(clicked(QModelIndex)),ui->listView,SLOT(setRootIndex(QModelIndex)));
connect(ui->treeView,SIGNAL(clicked(QModelIndex)),ui->tableView,SLOT(setRootIndex(QModelIndex)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actSetRootDir_triggered()
{
QString dir=QFileDialog::getExistingDirectory(this,"选择目录",QDir::currentPath());
if(dir.isEmpty())
return;
ui->treeView->setRootIndex(m_model->index(dir));
ui->listView->setRootIndex(m_model->index(dir));
ui->tableView->setRootIndex(m_model->index(dir));
}
void MainWindow::on_radOnlyDirAndFile_clicked()
{
ui->gbFilter->setEnabled(true);
m_model->setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot);
}
void MainWindow::on_radOnlyDir_clicked()
{
ui->gbFilter->setEnabled(false);
m_model->setFilter(QDir::AllDirs|QDir::NoDotAndDotDot);
}
void MainWindow::on_chkFliterFile_clicked(bool checked)
{
ui->comFileType->setEnabled(checked);
ui->btnApplicate->setEnabled(checked);
m_model->setNameFilterDisables(!checked);
}
void MainWindow::on_btnApplicate_clicked()
{
QStringList filter= ui->comFileType->currentText().trimmed().split(';',Qt::SkipEmptyParts);
m_model->setNameFilters(filter);
}
void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
ui->lbFileName->setText(m_model->fileName(index));
ui->lbDirName->setText(m_model->filePath(index));
ui->lbFileType->setText(m_model->type(index));
ui->chkIsDir->setChecked(m_model->isDir(index));
int sz=m_model->size(index)/1024;
if(sz<1024)
ui->lbFileSize->setText(QString("%1 KB").arg(sz));
else
ui->lbFileSize->setText(QString::asprintf("%.1f MB",sz/1024.0));
}