一、QStandardItemModel类的基本功能

  • QStandardItemModel是标准的以项数据为基础的标准数据模型类
  • QStandardItemModel通常与QTableView组合成数据模型,实现通用的二维数据的管理功能
  • QStandardItemModel维护一个二维的项数据数组,每个项是一个​QStandarItem类对象​,用于存储项的数据、字体格式、对齐方式等

二、QItemSelectionModel类

  • 概念:​一个用于跟踪视图组件的单元格选择状态的类。QTableView与QStandardItemModel数据模型组合后,在QTableView选择某个/多个单元格后,这些单元格就组合成一个QItemSelectionModel类对象
  • 是一个选择模型

三、QModelIndex、QModelIndexList类

  • QModelIndex:获得当前数据模型的索引,通过QModelIndex QStandardItemModel::index(int row, int column, const QModelIndex &parent = QModelIndex()) const、QModelIndex QItemSelectionModel::currentIndex() const函数获取,或者QModelIndexList的at函数获取
  • QModelIndexList:获得当前数据模型的索引集合,通过QModelIndexList QItemSelectionModel::selectedIndexes() const函数获得

四、常用函数

//通过数据模型索引获得QStandardItem 对象
QStandardItem *QStandardItemModel::itemFromIndex(const QModelIndex &index) const

//为QStandardItemModel数据模型设置表头
void QStandardItemModel::setHorizontalHeaderLabels(const QStringList &labels)

//为QStandardItemModel数据模型的指定行、列设置QStandardItem对象
void QStandardItemModel::setItem(int row, int column, QStandardItem *item)

//将QStandardItem对象设置为CheckBox状态(选中/未选中)
void QStandardItem::setCheckState(Qt::CheckState state)

//获取表头数据
QVariant QStandardItemModel::headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const

//在row行之前插入一个QList集合的对象
void QStandardItemModel::insertRow(int row, const QList<QStandardItem *> &items)

五、演示案例

Qt:26---QStandardItemModel数据模型_保存文件


功能实现

Qt:26---QStandardItemModel数据模型_数据_02

工具栏使用到的Action

Qt:26---QStandardItemModel数据模型_保存文件_03



类的定义

  • 类中的初始化变量、函数、宏定义

Qt:26---QStandardItemModel数据模型_数据_04



类构造函数

Qt:26---QStandardItemModel数据模型_数据_05



on_currentChanged槽函数

//鼠标选中tabView单元格变化时,在状态栏显示行、列号,内容等信息
void MainWindow::on_currentChanged(const QModelIndex &current,const QModelIndex &previous)
{
if(current.isValid())
{
LabCellPos->setText(QString::asprintf("current:%d row,%d col",current.row(),current.column()));
QStandardItem* aItem=theModel->itemFromIndex(current);//获得当前项对象
this->LabCellText->setText("Current content:"+aItem->text());//获得当前项的内容,并显示
QFont font=aItem->font();
ui->actFontBold->setChecked(font.bold());
}
}



文件打开triggered函数、与自定义函数iniModelFromStringList

  • 文件打开triggered的函数会打开一个已经书写规范的文件,然后读取这些文件的数据,存放在一个QStringList对象中,然后将QStringList对象作为iniModelFromStringList函数的参数调用该函数,然后iniModelFromStringList将这些数据显示到tabView中
  • 最后一列“测井取样”为布尔值,在设置tabView时,我们将最后一列设置为CheckBox对象
  • QString::split()函数用来分割成一个QString对象分割为QStringList对象

Qt:26---QStandardItemModel数据模型_数据_06Qt:26---QStandardItemModel数据模型_保存文件_07

void MainWindow::on_actOpen_triggered()
{
QString curPath=QCoreApplication::applicationDirPath();//获得当前路径
//打开一个文件
QString aFileName=QFileDialog::getOpenFileName(this,
QStringLiteral("打开一个文件"),curPath,QStringLiteral("井数据文件(*.txt);;所有文件(*.*)"));
if(aFileName.isEmpty())
return;
QStringList fFileContent;
QFile aFile(aFileName);//将打开的文件创建一个QFile对象
if(aFile.open(QIODevice::ReadOnly|QIODevice::Text))//以文本、只读的方式读取文件
{
QTextStream aStream(&aFile);
ui->plainTextEdit->clear();
while(!aStream.atEnd())//循环读取文件
{
QString str=aStream.readLine();//读取一行数据
ui->plainTextEdit->appendPlainText(str);
fFileContent.append(str);//将读取到的数据添加到QStringList对象中
}
aFile.close();
this->LabCurFile->setText(QStringLiteral("当前文件:")+aFileName);
iniModelFromStringList(fFileContent);
}
}

void MainWindow::iniModelFromStringList(QStringList &aFileContent)
{
int rowCnt=aFileContent.count();//获取文本的行数
theModel->setRowCount(rowCnt-1);

//设置表头,一个或多个空格、TAB等分隔符隔开的字符串,分解为一个StringList
QString header=aFileContent.at(0);//获取第一行数据,将数据作为tabView的表头
QStringList headerList=header.split(QRegExp("\\s+"),QString::SkipEmptyParts);//调用split函数分割数据
theModel->setHorizontalHeaderLabels(headerList);//将分割好的QStringList作为QStandardItemModel模型的表头数据

//设置表格数据
QStandardItem* aItem;//每一个项
QStringList tmpList;
int j;
for(int i=1;i<rowCnt;++i)//循环遍历行
{
//获取行数据,然后进行分割
QString aLineText=aFileContent.at(i);
tmpList=aLineText.split(QRegExp("\\s+"),QString::SkipEmptyParts);

for(j=0;j<FixedColumnCount-1;j++)//循环改行数据,并将每一项作为列数据
{
//不包含最后一列
aItem=new QStandardItem(tmpList.at(j));
theModel->setItem(i-1,j,aItem);
}
//最后一列
aItem=new QStandardItem(headerList.at(j));
aItem->setCheckable(true);//先将最后一列设置为选中
if(tmpList.at(j)=="0")//如果最后一列为0,则设置为未选中
aItem->setCheckState(Qt::Unchecked);
else//如果最后一列为1,则设置为选中
aItem->setCheckState(Qt::Checked);
theModel->setItem(i-1,j,aItem);//设置最后一列
}
}



添加行按钮触发函数(act_Append_triggered)

  • void QStandardItemModel::insertRow(int row, const QList<QStandardItem *> &items)  //该函数在row行之前插入一行数据,数据为参数2QList的集合
  • void QStandardItemModel::insertRow(int row, QStandardItem *item)  //该函数在row行之前插入一个QStandardItem对象

Qt:26---QStandardItemModel数据模型_数据模型_08

void MainWindow::on_actAppend_triggered()
{
QList<QStandardItem*> aItemList;//一个集合,用来保存QStandardItem项
QStandardItem *aItem;
//循环列数,只循环前5列,并且创建QStandardItem对象存放在QList集合中
for(int i=0;i<FixedColumnCount-1;++i)
{
aItem=new QStandardItem("0");//每一个项的内容初始化为0
aItemList<<aItem;
}

//因为最后一列为CheckBox,所以特殊处理
//获得最后一列的标头标题
QString str=theModel->headerData(theModel->columnCount()-1,Qt::Horizontal,
Qt::DisplayRole).toString();
aItem=new QStandardItem(str);//将标头标题设置为最后一列的内容
aItem->setCheckable(true);//最后一列设置为选择状态
aItemList<<aItem;

//在rowCount()行之前插入一行数据,aItemList为插入的集合
theModel->insertRow(theModel->rowCount(),aItemList);

//获得一行的索引
QModelIndex curIndex=theModel->index(theModel->rowCount()-1,0);
theSelection->clearSelection();//清除选择模型
//将当前的选择对象设置为最后一行
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}



插入行按钮触发函数(actInsert_triggered)

  • 与添加行按钮的代码类似,只是将insertRow的参数1改为当前选择的索引即可,就是在当前的索引处插入一行新数据



删除行按钮触发函数(​actDelete_triggered​)

  • bool QAbstractItemModel::removeRow(int row, const QModelIndex &parent = QModelIndex()) //删除指定的行
  • 下面的代码为什么要判断是否为最后一行,因为QStandardItemModel数据模型刚打开的时候是没有处于选择状态的

void MainWindow::on_actDelete_triggered()
{
QModelIndex curIndex=theSelection->currentIndex();//获取当前的模型索引
if(curIndex.row()==theModel->rowCount()-1)//如果选择的索引为最后一行
theModel->removeRow(curIndex.row());//删除最后一行
else//如果选择的不是最后一行
{
theModel->removeRow(curIndex.row());//删除改行
//重新设置模型索引
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
}



居左、居中、居右按钮触发函数(actAlignLeft_triggered)

  • setTextAlignment() //用来这是QStandardItem对象的对齐方式
  • 下面只演示向左对齐的,居中与向右对齐只需要改变setTextAlignment函数的参数即可

void MainWindow::on_actAlignLeft_triggered()
{
if(!theSelection->hasSelection())//如果当前没有选中单元格,直接退出
return;
//获取选中的单元格索引列表,存放在QModelIndexList对象中
QModelIndexList selectIndex=theSelection->selectedIndexes();
for(int i=0;i<selectIndex.count();++i)//遍历QModelIndexList对象
{
QModelIndex aIndex=selectIndex.at(i);//获取模型索引
QStandardItem* aItem=theModel->itemFromIndex(aIndex);//根据模型索引获得QStandardItem对象
aItem->setTextAlignment(Qt::AlignLeft);//设置该对象文字向左对齐
}
}



粗体按钮触发函数(actFontBold_triggered)

  • void QStandardItem::setFont(const QFont &font) //设置项的字体格式

void MainWindow::on_actFontBold_triggered()
{
if(!theSelection->hasSelection())//如果当前没有选中单元格,直接退出
return;
//获取 选中选中的单元格索引列表,存放在QModelIndexList对象中
QModelIndexList selectIndex=theSelection->selectedIndexes();
for(int i=0;i<selectIndex.count();++i)//遍历QModelIndexList对象
{
QModelIndex aIndex=selectIndex.at(i);//获取模型索引
QStandardItem* aItem=theModel->itemFromIndex(aIndex);//根据模型索引获得QStandardItem对象
QFont font=aItem->font();//获得字体对象
font.setBold(true);//将字体为粗体
aItem->setFont(font);//为该项设置字体对象
}
}



另存文件按钮触发函数(actSave_triggered)

  • 点击该按钮,可以将数据模型的数据另存为一个数据文本文件,同时也显示在PlainTextEdit里
  • 注意:该函数还有问题,待解决

void MainWindow::on_actSave_triggered()
{
QString curPath=QCoreApplication::applicationDirPath();//获得当前路径
QString aFileName=QFileDialog::getSaveFileName(this,QStringLiteral("选择一个文件"),
curPath,QStringLiteral("井斜数据文件(*.txt);;所有文件(*.*)"));//设置一个保存文件
if(aFileName.isEmpty())
return;
QFile aFile(aFileName);//为保存文件设置QFile对象
if(!(aFile.open(QIODevice::ReadWrite|QIODevice::Text|QIODevice::Truncate)))
return;
QTextStream aStream(&aFile);//为保存文件设置文件流对象

QStandardItem* aItem;
int i,j;
QString str;//创建一个QString对象,用来保存
ui->plainTextEdit->clear();

for(int i=0;i>theModel->columnCount();++i)//遍历列数
{
aItem=theModel->horizontalHeaderItem(i);//先将表头数据保存到QString中
str=str+aItem->text()+"\t";
}
aStream<<str<<"\n";//换行
ui->plainTextEdit->appendPlainText(str);

for(i=0;i<theModel->rowCount();++i)//遍历行数
{
str="";
for(j=0;i<theModel->columnCount()-1;j++)//遍历列数,不包括最后一列
{
aItem=theModel->item(i,j);
str=str+aItem->text()+QString::asprintf("\t");
}
//最后一列特殊处理
aItem=theModel->item(i,j);
if(aItem->checkState()==Qt::Checked)
str=str+"1";
else
str=str+"0";
ui->plainTextEdit->appendPlainText(str);
aStream<<str<<"\n";
}
}



数据模型预览按钮触发函数

  • 与数据另存为文件按钮的功能类似,就是将数据模型的数据显示到右侧的PlainTextEdit里面