一、三者关系
1.QStanardItemModel
1) QStandardItemModel是基于项的模型类,每个项是QStanardItem对象,它与QTableView组成模型视图/结构,可以实现二维数组的管理。
2.QStandardItem
1) QStandardItem存储乐一个项的各种特性参数,也可以存储用户自定义数据。
2)一个项可以添加子项,子项也可以是QStanardItem类型的对象,QStandardItem也可以作为树状模型的项。
3.QTableView
1)二维表格试图组件类,基本显示单元是单元格。
2)setModle() 可设置一个QStanardItemModel类的数据模型,之后一个单元格显示数据模型中的一个项目。
4.QItemSelectionModel
1)选择模型,可通过setModel()为选择模型设置数据类型。
2)用于跟踪视图组件上的选择操作,给出选择范围。
二、实现
1.窗口类定义和初始化
1)头文件class声明,在.c文件引入头文件。
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QToolBar *toolBarAbove;
QLabel *lab;//当前文件
QLabel *labFile;//显示文件路径
QLabel *lab2;//当前单元格坐标
QLabel *labCoord;//显示单元格坐标
QLabel *lab3;//单元格内容
QLabel *labInformation;//显示单元格内容
QStandardItemModel *m_stdItemModel;//数据模型
QItemSelectionModel *m_itemSelModel;//选择模型
const int FixedColumnCount=6;//列
void toolbarIni();//工具栏初始化
void statusbarIni();//状态栏初始化
void newRowini(QModelIndex *modelindex);//新行初始化
void iniModelData(QStringList &aFileContent);//从stringList初始化数据模型内容
private slots:
void do_currentChanged(const QModelIndex ¤t,const QModelIndex &previous);//只做址传递,存储地址,使用‘&’ 作用:当选项发生变化时
void do_act_addRow_triggered();//添加行
void do_act_insertRow_triggered();//插入行
void on_act_deleteRow_triggered();//删除行
void do_act_open_triggered();//打开文件
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
2.c文件主函数初始化
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//QStandardItemModel 基于项数据的标准数据模型,维护一个二维的项数据数组,每个项是一个 QStandardltem 类的变量,用于存储项的数据、字体格式、对齐方式等
m_stdItemModel =new QStandardItemModel(2,FixedColumnCount,this);
//QItemSelectionModel 二维数据表视图组件,有多个行和多个列,每个基本显示单元是一个单元格
//通过 setModel() 函数设置一个 QStandardItemModel 类的数据模型之后,一个单元格显示 QStandardItemModel 数据模型中的一个项
m_itemSelModel=new QItemSelectionModel(m_stdItemModel);
ui->tableView->setModel(m_stdItemModel);//要设置的数据模型,m_stdItemModel(QStandardItemModel模型)
ui->tableView->setSelectionModel(m_itemSelModel);//设置选择模型
ui->tableView->setAlternatingRowColors(true);//允许扩展选择多个单元格
// 函数:void setSelectionMode(QAbstractItemView::SelectionMode mode);设置选择模式类型
//SelectionMode:一个用于跟踪视图组件的单元格选择状态的类
// NoSelection (0): 不能选择任何项。
// SingleSelection (1): 只能选择一项,选中项与当前项为同一项,可以通过Ctrl+Click取消选择。
// MultiSelection (2): 选中一项时,该项的选择状态将被改变,不影响其他项。可通过拖动鼠标选择多项。
// ExtendedSelection (3): 正常选择时,一次选择一项。Ctrl+Click可以改变选中项的选择状态而不影响其他项的选择状态,Shift+Click可以根据选中项的状态决定选中项和当前项间所有项的状态。可以通过拖动鼠标选择多项。
// ContiguousSelection (4): 正常选择时,一次选中一项。当结合Shift+Click选中某项时,选中项和当前项(即上一次的选中项)间的所有项将同时被选中或取消,这取决于选中项的状态。
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);//设置tableView
//SelectItems 选择单个项目
//SelectRows 仅选择行
//SelectColumns 仅选择列
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);//选择单个项目
toolbarIni();//工具栏初始化
statusbarIni();//状态栏初始化
//信号和槽
connect(m_itemSelModel,SIGNAL(currentChanged(const QModelIndex,const QModelIndex)),this,SLOT(do_currentChanged(const QModelIndex, const QModelIndex)));
connect(ui->act_addRow,SIGNAL(triggered()),this,SLOT(do_act_addRow_triggered()));
connect(ui->act_insertRow,SIGNAL(triggered()),this,SLOT(do_act_insertRow_triggered()));
connect(ui->act_open,SIGNAL(triggered()),this,SLOT(do_act_open_triggered()));
connect(m_stdItemModel,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(modeldataChanged(QStandardItem*)));//数据模型内的数据变化
intspinBoxDelegate=new TSpinBoxDelegate(this);
//设置委托
ui->tableView->setItemDelegateForColumn(0,intspinBoxDelegate);//为测深设置委托
floatSpinDelegate=new TFloatSpinDelegate(this);
//设置委托
ui->tableView->setItemDelegateForColumn(1,floatSpinDelegate);//垂深
ui->tableView->setItemDelegateForColumn(2,floatSpinDelegate);//方位
ui->tableView->setItemDelegateForColumn(3,floatSpinDelegate);//总位移
comboBoxDelegate=new TComboBoxDelegate(this);
QStringList strList;
strList<<"优"<<"良"<<"可"<<"不合格";
comboBoxDelegate->setItems(strList,false);
ui->tableView->setItemDelegateForColumn(4,comboBoxDelegate);
}
3.工具栏初始化
void MainWindow::toolbarIni()//工具栏初始化
{
toolBarAbove=this->addToolBar("工具栏");//添加工具栏
toolBarAbove->setAllowedAreas(Qt::TopToolBarArea);//设置工具栏在菜单栏下面
toolBarAbove->setIconSize(QSize(30,30));
QIcon icon1(":/actIcon/icon/iocn1.png");//定义icon
ui->act_open->setIcon(icon1);
toolBarAbove->addAction(ui->act_open);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon2(":/actIcon/icon/iocn2.png");
ui->act_preview->setIcon(icon2);
ui->act_preview->setCheckable(true);
toolBarAbove->addAction(ui->act_preview);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon3(":/actIcon/icon/iocn3.png");
ui->act_addRow->setIcon(icon3);
toolBarAbove->addAction(ui->act_addRow);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon4(":/actIcon/icon/iocn4.png");
ui->act_insertRow->setIcon(icon4);
toolBarAbove->addAction(ui->act_insertRow);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon5(":/actIcon/icon/iocn5.png");
ui->act_deleteRow->setIcon(icon5);
toolBarAbove->addAction(ui->act_deleteRow);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon6(":/actIcon/icon/iocn6.png");
ui->act_left->setIcon(icon6);
toolBarAbove->addAction(ui->act_left);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon7(":/actIcon/icon/iocn7.png");
ui->act_middle->setIcon(icon7);
toolBarAbove->addAction(ui->act_middle);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon8(":/actIcon/icon/iocn8.png");
ui->act_right->setIcon(icon8);
toolBarAbove->addAction(ui->act_right);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon9(":/actIcon/icon/iocn9.png");
ui->act_bold->setIcon(icon9);
toolBarAbove->addAction(ui->act_bold);
ui->act_bold->setCheckable(true);
toolBarAbove->addSeparator();//添加分隔条
QIcon icon10(":/actIcon/icon/iocn10.png");
ui->act_exit->setIcon(icon10);
toolBarAbove->addAction(ui->act_exit);
toolBarAbove->addSeparator();//添加分隔条
}
4.状态栏初始化
void MainWindow::statusbarIni()
{
lab=new QLabel("当前文件:");
lab2=new QLabel("当前单元格:");
lab3=new QLabel("单元格内容:");
labFile=new QLabel(this);
labFile->setMinimumWidth(320);
labCoord=new QLabel(this);
labCoord->setMinimumWidth(50);
labInformation=new QLabel(this);
labInformation->setMinimumWidth(50);
//逐个添加
ui->statusbar->addWidget(lab);
ui->statusbar->addWidget(labFile);
ui->statusbar->addWidget(lab2);
ui->statusbar->addWidget(labCoord);
ui->statusbar->addWidget(lab3);
ui->statusbar->addWidget(labInformation);
}
5.打开文件
//打开文件
void MainWindow::do_act_open_triggered()
{
QString curPath=QCoreApplication::applicationFilePath();//用于获取应用程序的路径
QString aFileName=QFileDialog::getOpenFileName(this,"打开一个文件",curPath,"数据文件(*.txt);;所有文件(*.*)");//接受文件路径
ui->lineEdit->setText(aFileName);
if(aFileName.isEmpty())
return;//空文件退出
QStringList aFileContent;
QFile aFile(aFileName);
if(aFile.open(QIODevice::ReadOnly | QIODevice::Text))//以只读文本方式打开文件
{
QTextStream aStream(&aFile);
ui->plainTextEdit->clear();//清空文本,避免之前数据影响
while(!aStream.atEnd())//不到末尾不退出
{
QString str=aStream.readLine();//读取一行
ui->plainTextEdit->appendPlainText(str);//显示一行
aFileContent.append(str);//向stringList容器添加数据
}
aFile.close();
/* .h文件的定义信息
QLabel *lab;//当前文件
QLabel *labFile;//显示文件路径
QLabel *lab2;//当前单元格坐标
QLabel *labCoord;//显示单元格坐标
QLabel *lab3;//单元格内容
QLabel *labInformation;//显示单元格内容
*/
labFile->setText(aFileName);//状态栏更新
iniModelData(aFileContent);//自定义函数,从QStringList读取
}
}
6.iniModelData() 从stringList读取数据
1)出现文件可以打开,但是读取的数据乱码的情况,可以将txt文档另存为的同时换另一个编码格式
void MainWindow::iniModelData(QStringList &aFileContent)//从QStringList读取文件
{
m_stdItemModel->clear();//清空数据模型
qDebug()<<"iniModeData emit!!";
int rowCnt=aFileContent.size();//统计文本行数
m_stdItemModel->setRowCount(rowCnt-1);//实际的行数
QString header=aFileContent.at(0);//第一行,指向表头文字
QStringList headerList=header.split(QRegularExpression(",|,|\\s+"),Qt::SkipEmptyParts);//以中英文逗号和空格隔开,不保留空行数据。+表示一个或多个
qDebug()<<"headerList="<<headerList.size();
m_stdItemModel->setHorizontalHeaderLabels(headerList);//设置表头文字
//设置表格数据
int j;
QStandardItem *aItem;
for(int i=1;i<rowCnt;i++)
{
QString aLineText=aFileContent.at(i);
QStringList tmpList=aLineText.split(QRegularExpression(",|,|\\s+"),Qt::SkipEmptyParts);
qDebug()<<tmpList.size();//分割出来的个数
if(tmpList.size() != aFileContent.size())//如果不等于原始数据的大小,表示缺少列
{
for(j=0;j<tmpList.size()-1;j++)
{
tmpList[j]="dataError";//标明错误数据
}
}
for(j=0;j<tmpList.size()-1;j++)
{
aItem=new QStandardItem(tmpList.at(j));
m_stdItemModel->setItem(i-1,j,aItem);//i行,j列,逐个添加项
}
if(j==m_stdItemModel->columnCount()-1)//如果确实在最后一行
{
aItem=new QStandardItem(headerList.at(j));//此列
aItem->setCheckable(true);
aItem->setBackground(QBrush(Qt::yellow));//设置背景
if(tmpList.at(j)=="0")
aItem->setCheckState(Qt::Unchecked);//不勾选
else
aItem->setCheckState(Qt::Checked);//勾选
}
m_stdItemModel->setItem(i-1,j,aItem);//添加i行最后一列
}
if(!ui->act_preview->isChecked())//如果数据浏览Action没有勾选
ui->plainTextEdit->clear();//立刻清除,不显示
}

7.数据浏览
//数据浏览
void MainWindow::on_act_preview_triggered(bool checked)
{
if(checked)
{
//显示
QStandardItem *aItem=m_stdItemModel->item(0,0);
modeldataChanged(aItem);//自定义函数,当有数据变化
}
else
ui->plainTextEdit->clear();
}
8.数据变化
//数据模型发生变化时,更新数据
void MainWindow::modeldataChanged(QStandardItem* aItem)
{
if(!ui->act_preview->isChecked())//判断是否再plainTextEidt上显示数据
return;//没选中,不显示数据
ui->plainTextEdit->clear();
int m_row=m_stdItemModel->rowCount();//行
int m_column=m_stdItemModel->columnCount();//列
qDebug()<<"行:"<<m_row<<"列:"<<m_column;
QStringList str;//记录模型数据
for(int i=0;i<m_column;i++)
{
if(m_stdItemModel->horizontalHeaderItem(i)==nullptr)
return;//如果为空,直接退出
str.append(m_stdItemModel->horizontalHeaderItem(i)->text());//加入表头
}
qDebug()<<"加入表头ok";
for(int i=0;i<m_row;i++)
{
for(int j=0;j<m_column;j++)
{
QModelIndex aIndex=m_stdItemModel->index(i,j);//获取模型索引
aItem=m_stdItemModel->itemFromIndex(aIndex);//根据索引获取单元格项目
if(j==m_column-1)
{
qDebug()<<"计数末尾:"<<aItem->text();
if(aItem->checkState()==Qt::Checked)
str.append("1");
else
str.append("2");
break;
}
str.append(aItem->text());
}
}
qDebug()<<"读取数据ok";
int k=1;
QString aStr;
for(QStringList::iterator i=str.begin();i!=str.end();i++,k++)
{
aStr.append(*i);
if(k%m_column==0)
{
ui->plainTextEdit->appendPlainText(aStr);//打印
aStr.clear();//清空
}
else
{
aStr.append('\t');//不是列尾,添加水平制表位
}
}
qDebug()<<"打印数据ok";
}
9.信号和槽
//信号和槽
connect(m_itemSelModel,SIGNAL(currentChanged(const QModelIndex,const QModelIndex)),this,SLOT(do_currentChanged(const QModelIndex, const QModelIndex)));
connect(ui->act_addRow,SIGNAL(triggered()),this,SLOT(do_act_addRow_triggered()));
connect(ui->act_insertRow,SIGNAL(triggered()),this,SLOT(do_act_insertRow_triggered()));
connect(ui->act_open,SIGNAL(triggered()),this,SLOT(do_act_open_triggered()));
connect(m_stdItemModel,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(modeldataChanged(QStandardItem*)));//数据模型内的数据变化
10.添加插入新行
//添加新行
void MainWindow::newRowini(QModelIndex *modelindex)
{
//获取表格信息,初始化添加行数据
int a_columCount=m_stdItemModel->columnCount();//获取表格列
//存储数据
QList<QString> *list=new QList<QString>;
for(int i=0;i<a_columCount;i++)
{
list->push_back("InsertRow");//尾部添加数据
QStandardItem* aitem=new QStandardItem;//创建item用来存储单独item(单元格)数据
aitem->setText(list->at(i));//设置item(单元格)信息
m_stdItemModel->setItem(modelindex->row(),i,aitem);//设置newRow行,i列,表格单元的数据
}
QStandardItem* insertInformation=new QStandardItem;
//添加新行,NowRow行添加insertInformation的单元格模型
//内部item更新后,QStandardItemModel添加一个新行
m_stdItemModel->insertRow(modelindex->row(),insertInformation);
//*********************************************************************************************
//********************************************************************************************
QModelIndex index=*modelindex;//取 传入的 modelindex 的 const QModelIndex &index **
ui->tableView->setCurrentIndex(index);//随添加行,但使选中的行index不变 **
//******************************************************************************************
//*****************************************************************************************
}
//添加行
void MainWindow::do_act_addRow_triggered()
{
int colcount=m_stdItemModel->columnCount();//获取列数
qDebug()<<QString("%1").arg(colcount);
const QList<QStandardItem*> addInformation;
m_stdItemModel->appendRow(addInformation);
}
//插入行
void MainWindow::do_act_insertRow_triggered()
{
//提示函数触发
qDebug()<<"do_act_insertRow_triggered is emit!";
//是否有单元格选中
if(m_itemSelModel->hasSelection()==false)
{
return;
}
//获取表格选中位置
QModelIndex modelindex=ui->tableView->currentIndex();//获取选中行
int NowRow=modelindex.row();
qDebug()<<NowRow;
newRowini(&modelindex);
}
11.字体设置与段落设置
1)判断选择选择模型提供的选择范围是否为空,再取出项,对字体设置。
2)将获取的索引存储到一个容器当中
QModelIndexList aIndexList=m_itemSelModel->selectedIndexes();//获取索引
3)段落同上(靠左、靠右、居中)。
//靠左
void MainWindow::on_act_left_triggered()
{
if(!m_itemSelModel->hasSelection())//没有选择项
return;//退出
QModelIndexList IndexList=m_itemSelModel->selectedIndexes();//获取选择的单元格的模型索引列表(可多选)
for(int i=0;i<IndexList.count();i++)
{
QModelIndex aIndex=IndexList.at(i);//获取一个模型索引
QStandardItem* aItem=m_stdItemModel->itemFromIndex(aIndex);//根据模型索引获取单元格的项
aItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);//设置靠左,垂直居中
}
}