本文作者原创首发于CSDN,本文原创请勿转载
版权声明:本文为CSDN博主「双子座断点」的原创文章,遵循CC 4.0 BY-SA版权协议。
原文链接:https://blog.csdn.net/qq_37529913/article/details/110127940
1. 项目结构&软件界面
2. mainwindow.h文件
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStandardItemModel>
#include <QDebug>
#include <QFile>
#include <QMessageBox>
#include <QModelIndex>
#include <QFileDialog>
#include <functional>
#include <QItemSelectionModel>
//引入头文件
#include "mythread.h"
//加入GBK申明,否则中文乱码 全局使用GBK文件操作因为有中文所以使用utf-8
#pragma execution_character_set("gbk")
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void ioDemo(); //初始化 删除修改添加之后也会调用初始化函数
void deleteOnelineInFile(int nNumLine, QString &filename); //删除函数
void DeleteOneline(int nNum, QString &strall); //删除函数
QLabel *LabCurFile; //当前文件
QLabel *LabCellPos; //当前单元格行列号
QLabel *LabCellText; //当前单元格内容
/* 创建数据模型 */
QStandardItemModel* model = new QStandardItemModel();
QItemSelectionModel *theSelection; //选择模型
private slots:
void on_tableView_activated(const QModelIndex &index);
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_Button_File_clicked();
//当前选择单元格发生变化
void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
void OnlineTreeViewDoubleClick(const QModelIndex & index);
private:
Ui::MainWindow *ui;
//初始化
mythread * thread;
//update的行
QString strUpItem="";
};
#endif // MAINWINDOW_H
3. 构造函数
//构造函数
thread = new mythread; //分配空间
//关联信号获取结束线程信号
connect(thread, &mythread::isDone, this, &MainWindow::addSave);
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//不可编辑
//ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选中模式为选中行
//ui->tableView->setSelectionMode( QAbstractItemView::SingleSelection);//设置选中单个
//QTableWidget类似
4. 打开文件
{
/*
//Button_File
//定义文件对话框类
QFileDialog *fileDialog = new QFileDialog(this);
//定义文件对话框标题
fileDialog->setWindowTitle(QStringLiteral("选中文件"));
//设置默认文件路径
fileDialog->setDirectory(".");
//设置文件过滤器
fileDialog->setNameFilter(tr("File(*.*)"));
//设置可以选择多个文件,默认为只能选择一个文件QFileDialog::ExistingFiles
fileDialog->setFileMode(QFileDialog::ExistingFiles);
//设置视图模式
fileDialog->setViewMode(QFileDialog::Detail);
//打印所有选择的文件的路径
QStringList fileNames;
if (fileDialog->exec()) {
fileNames = fileDialog->selectedFiles();
qDebug()<<fileNames;
}
*/
//QFile writeFile("E:/QT/Creator/QT_MySQL/aa.txt"); //PATH是自定义写文件的地址
QString fileName = QFileDialog::getOpenFileName(this,"文件对话框!",".","Text files (*.txt);;Any files (*)");
ui->lineEdit_5->setText(fileName);
//QString fileName = QFileDialog::getExistingDirectory(NULL,"caption",".");
//ui->lineEdit_5->setText(fileName);
//6. 初始化QtableView控件
ioDemo();
}
5. 实现监听事件
第一个if是用来获取某一个单元格的X Y位置以及对应的Value值。
for 中的 3对应着 tableview的列,因为本文数据源有三列所以就直接写死了,后期需要可以设置两个全局变量代替。
最上方注释的代码是原型代码。
{
/*
//原型代码
//选择单元格变化时的响应
if (current.isValid())
{
LabCellPos->setText (QString::asprintf ("当前单元格:%d 行,%d 列", current.row(),current.column()));
QStandardItem* aItem=theModel->itemFromIndex(current);
this->LabCellText->setText ("单元格内容:"+aItem->text());
QFont font=aItem->font();
ui->actFontBold->setChecked(font.bold());
}
*/
if (current.isValid())
{
//LabCellPos->setText (QString::asprintf ("当前单元格:%d 行,%d 列", current.row(),current.column()));
qDebug()<<"当前单元格:";
qDebug()<<QString::number(current.row())<<" 行,";
//qDebug()<<QString::number(current.column())<<" 列";
QStandardItem* aItem=model->itemFromIndex(current);
//this->LabCellText->setText ("单元格内容:"+aItem->text());
qDebug()<<"单元格内容:"<<aItem->text();
QFont font=aItem->font();
qDebug()<<font.bold();
//ui->actFontBold->setChecked(font.bold());
}
strUpItem="";
for(int i=0;i<3;i++){
QModelIndex rootIndex = ui->tableView->model()->index(current.row(), i);//最顶层item的index
QStandardItem* aItem=model->itemFromIndex(rootIndex);
qDebug()<<"2.单元格内容:"<<aItem->text();
strUpItem += aItem->text();
}
qDebug()<<"2.单元格所选内容:" << strUpItem;
/*
strUpItem="";
for(int i=0;i<3;i++){
QModelIndex rootIndex = ui->tableView->model()->index(-1, i);//最顶层item的index
QStandardItem* aItem=model->itemFromIndex(rootIndex);
qDebug()<<"3.单元格内容:"<<aItem->text();
strUpItem += aItem->text();
}
qDebug()<<"3.单元格所选内容:" << strUpItem;
*/
}
6. 初始化QtableView控件
QAbstractItemView参考:Qt QStandardItemModel(1.超级详细用法)_双子座断点的博客-CSDN博客_qstandardmodel
QAbstractItemView查找函数参考:Qt QStandardItemModel(2.超级详细函数)_双子座断点的博客-CSDN博客_qstandarditemmodel点击事件
修改样式参考:https://blog.csdn.net/QIJINGBO123/article/details/84186352
下方数据模型设置部分需要添加函数可以点击QAbstractItemView查找函数进行参考查看
void MainWindow::ioDemo()
{
QFile file(ui->lineEdit_5->text());
ui->tableView->setModel(model);
/* 设置表格标题行(输入数据为QStringList类型) */
model->setHorizontalHeaderLabels({"学号", "姓名", "考试题目"});
/* 自适应所有列,让它布满空间 */
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
if(! file.open(QIODevice::ReadOnly|QIODevice::Text))
qDebug()<<file.errorString();
else
qDebug()<<"openok";
file.seek(0);
QTextStream shuru(&file);
shuru.setCodec("utf-8"); // 设置文件的编码格式为utf-8
int ioInt=0;
QString strID,strName,School;
while(! shuru.atEnd())
{
QString line=shuru.readLine();
qDebug()<<line;
model->setItem(ioInt, 0, new QStandardItem(line.left(1)));
model->setItem(ioInt, 1, new QStandardItem(line.mid(1,3)));
model->setItem(ioInt, 2, new QStandardItem(line.mid(4,8)));
ioInt++;
}
/* 设置表格视图数据 */
ui->tableView->setModel(model);
/* 显示 */
ui->tableView->show();
file.close();
//数据模型
theSelection = new QItemSelectionModel (model) ;//选择模型
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)), this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
ui->tableView->setSelectionModel(theSelection); //设置选择模型
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
//ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选中模式为选中行
ui->tableView->setSelectionMode ( QAbstractItemView::SingleSelection);//禁止选择多行
}
7. 实现修改功能
如果进行删除操作的话,删除会导致数据删除换行符还有存留。
添加操作的话可能会导致添加完后再次添加可能会添加至下下行。
void MainWindow::on_pushButton_3_clicked()
{
QString strAll;
QStringList strList;
QFile readFile(ui->lineEdit_5->text());
if(readFile.open((QIODevice::ReadOnly|QIODevice::Text)))
{
//把文件所有信息读出来
QTextStream stream(&readFile);
stream.setCodec("utf-8"); // 设置文件的编码格式为utf-8
strAll=stream.readAll();
}
readFile.close();
QFile writeFile(ui->lineEdit_5->text());
if(writeFile.open(QIODevice::WriteOnly|QIODevice::Text))
{
QTextStream stream(&writeFile);
stream.setCodec("utf-8"); // 设置文件的编码格式为utf-8
strList=strAll.split("\n"); //以换行符为基准分割文本
for(int i=0;i<strList.count();i++) //遍历每一行
{
//strUpItem 全局变量,在鼠标选中行后自动获取value
if(strList.at(i).contains(strUpItem))
{
if(i==strList.count()-1){
QString tempStr=strList.at(i);
tempStr.replace(0,tempStr.length(),ui->lineEdit_4->text()); //"Hello!"是要替换的内容
stream<<tempStr<<'\n';
}
else{
QString tempStr=strList.at(i);
tempStr.replace(0,tempStr.length(),ui->lineEdit_4->text()); //"Hello!"是要替换的内容
stream<<tempStr<<'\n';
}
}
//如果没有找到要替换的内容,照常写入
else
{
if(i==strList.count()-1)
{
stream<<strList.at(i);
}
else
{
stream<<strList.at(i)<<'\n';//添加<<'\n'换行
}
}
}
}
writeFile.close();
ioDemo();
}
8. 实现添加功能
{
QFile file(ui->lineEdit_5->text());
QString n1;
if (file.open(QIODevice::ReadWrite | QIODevice::Append))
{
QTextStream txtOutput(&file);
txtOutput.setCodec("utf-8"); // 设置文件的编码格式为utf-8
n1="\n"+ui->lineEdit->text()+" "+ui->lineEdit_2->text()+" "+ui->lineEdit_3->text();
txtOutput << n1 << endl;
file.close();
}
file.close();
ioDemo();
}
9. 实现删除功能
void MainWindow::on_pushButton_2_clicked()
{
QString str=ui->lineEdit_5->text();
deleteOnelineInFile(ui->tableView->currentIndex().row(),str);
//重新初始化视图
ioDemo();
//删除多行
/*
出自https://blog.csdn.net/qq_40450386/article/details/82904934
QItemSelectionModel *model_selection = ui->tableView->selectionModel();
QModelIndexList IndexList= model_selection->selectedIndexes();
QMap<int,int>rowMap;
foreach (QModelIndex index, IndexList)
{
//处理略 ... 可以读取、修改其内容;
}
上面代码中QModelIndexList记录的是所有选中的item的index,而不是行的index,不管你的选中模式是行还是item;
如果想对整行处理的话,需要避免对同一行多次操作;比如可以index.column()==0时进行操作处理;
如果删除选中的多行,更需要当心进坑!model.removeRow(row)之后,之后的行号就变了(减少1),可不幸的是,选中记录里的行号没有变化,还是原来的行号,再进行删除就删错行了。(比如,要删除2,4行,删了第2行后,原来的第4行变成了第3行,可是你删除的还是记录里的第4行!)所以删除多个行时,要从后往前删除,先删除行号大的,对小的没影响。
可以用Qmap记录删除的行,因为他是排序的,省去麻烦
删除多行完整代码如下:
QItemSelectionModel *model_selection = ui->tableView->selectionModel();
QModelIndexList IndexList= model_selection->selectedIndexes();
QMap<int,int>rowMap;
foreach (QModelIndex index, IndexList)
{
if(! index.isValid()) return;
if(index.column()!=0) continue;
rowMap.insert(index.row(),0);
}
QMapIterator<int,int> Iterator(rowMap);
Iterator.toBack();
while(rowMapIterator.hasPrevious())
{
rowMapIterator.previous();
int rowm=rowMapIterator.key();
qDebug()<<"del row..."<<rowm;
file_model->removeRow(rowm);
}
*/
}
void MainWindow::deleteOnelineInFile(int nNumLine, QString &filename)
{
//删除model中的一行视图数据
model->removeRow(nNumLine);
QString strall;
QFile readfile(filename);
if(readfile.open(QIODevice::ReadOnly))
{
QTextStream stream(&readfile);
strall=stream.readAll();
}
readfile.close();
DeleteOneline(nNumLine, strall);
//删除File文件内的某一行数据
QFile writefile(ui->lineEdit_5->text());
if(writefile.open(QIODevice::WriteOnly))
{
QTextStream wrtstream(&writefile);
// --\n
wrtstream << strall;
}
writefile.close();
}
void MainWindow::DeleteOneline(int nNum, QString &strall)
{
int nLine=0;
int Index=0;
//算出行数nLine
while(Index!=-1)
{
Index=strall.indexOf('\n',Index+1);
nLine++;
}
//如果是直接从位置0开始删除\n算一个字符"abc\nme\ndo" \n的index是3要删除3+1个字符,即index+1个
if(nNum==0)
{
int nIndex=strall.indexOf('\n');
strall.remove(0,nIndex+1);
}
else
{
int nTemp=nNum;
int nIndex=0,nIndex2=0;
while(nTemp--)
{
//
nIndex=strall.indexOf('\n',nIndex+1);//这里会更新nIndex
if(nIndex!=-1)//说明是有效的
{
nIndex2=strall.indexOf('\n',nIndex+1);
}
}
//删除的行不是最后一行(从nIndex+1这个位置起nIndex2-nIndex个字符全部抹去)
if(nNum<nLine-1)
{
strall.remove(nIndex+1, nIndex2-nIndex);//不用减一
}
//删除的是最后一行(从nIndex起始len-nIndex个字符全抹去)
//不能从nIndex+1处开始,
else if(nNum==nLine-1)
{
int len=strall.length();
strall.remove(nIndex,len-nIndex);
}
else
{
}
}
}
10. 功能演示
本文代码就不放出来了,自己加油加油照着做就可以做出来了。
本文借鉴参考: Qt QStandardItemModel用法(超级详细),其它博客就别瞎看了,参考作者的文章和C语言网的这篇文章是最正确的。
雷总看了都说Nice的文章,看完记得点关注哈~