一.前言
书接上回,我们已经实现了导入文件,添加行,插入行,删除行,接下来,我们开始实现接下来的功能。
二.预览数据
1.获取表头
void MainWindow::on_actionSee_triggered() { ui->plainTextEdit->clear();//把上次显示的清空 QString str; for(int i=0;i<colCount;i++) { auto item=model->horizontalHeaderItem(i);//拿到表头的每项数据 str+=item->text()+"\t\t";//将每项的内容加到字符串中 } ui->plainTextEdit->appendPlainText(str);//添加到文本编辑器里 }
运行结果:
2.获取数据项
接下来就是拿到数据项了,表格类似于二维数组,所有我们可以用两次for循环来拿。
for(int i=0;i<model->rowCount();i++) { str="";//每一行都从空字符串相加 for(int j=0;j<colCount-1;j++)//最一列单独处理 { auto item=model->item(i,j); str+=item->text()+"\t\t"; } auto item=model->item(i,colCount-1);//最后一列 if(item->checkState()==Qt::Checked)//根据是否勾选来选择 { str+="是"; } else { str+="否"; } ui->plainTextEdit->appendPlainText(str);//会自动换行 }
运行结果:
三.保存文件
1.文件对话框获取保存文件名
//获取保存文件名 QString fileName=QFileDialog::getSaveFileName(this,"保存文件",QCoreApplication::applicationDirPath());
防御性编程:
if(fileName.isEmpty())//如果文件名为空,就直接返回 { return; }
2.用文件名初始化文件对象
QFile qFile(fileName);
3.打开文件对象
用读写和文本和截断的方式打开,截断就是打开时里面有文件就清空
if(!qFile.open(QIODevice::ReadWrite|QIODevice::Text|QIODevice::Truncate))//通过打不开文件直接返回 { return; }
4.用文件对象初始化文本流
QTextStream stream(&qFile);
5.写入数据
其实就跟刚刚预览数据的时候一样,只是这里是往文件里面进行添加
QString str; for(int i=0;i<colCount;i++) { auto item=model->horizontalHeaderItem(i);//拿到表头的每项数据 str+=item->text()+"\t\t";//将每项的内容加到字符串中 } stream<<str<<"\n";//写入文件中 for(int i=0;i<model->rowCount();i++) { str="";//每一行都从空字符串相加 for(int j=0;j<colCount-1;j++)//最一列单独处理 { auto item=model->item(i,j); str+=item->text()+"\t\t"; } auto item=model->item(i,colCount-1); if(item->checkState()==Qt::Checked) { str+="是"; } else { str+="否"; } stream<<str<<"\n";//写入文件中
运行结果保存的文:
四.格式
1.居右
默认单元格内容居左,所以我们先来实现居右的功能
void MainWindow::on_actionRight_triggered() { if(!selectionModel->hasSelection())//没有选择就直接退出 { return; } auto indexs=selectionModel->selectedIndexes();//通过选择模型可以获取选择的多个单元格的模型索引 for(int i=0;i<indexs.count();i++) { QStandardItem * item=model->itemFromIndex(indexs[i]);//通过模型索引获取项 item->setTextAlignment(Qt::AlignVCenter|Qt::AlignRight);//设置文本对其方式为右对其,垂直居中 } }
注释我写的很详细我就不讲了,auto是我偷懒的写法,如果你们要写具体的类型可以点进函数看。
2.居中
同理,只是文本对齐参数不一样
void MainWindow::on_actionMiddle_triggered() { if(!selectionModel->hasSelection())//没有选择就直接退出 { return; } auto indexs=selectionModel->selectedIndexes();//通过选择模型可以获取选择的多个单元格的模型索引 for(int i=0;i<indexs.count();i++) { QStandardItem * item=model->itemFromIndex(indexs[i]);//通过模型索引获取项 item->setTextAlignment(Qt::AlignVCenter|Qt::AlignHCenter);//只是这里参数不一样 } }
运行结果:
3.居左
void MainWindow::on_actionLeft_triggered() { if(!selectionModel->hasSelection())//没有选择就直接退出 { return; } auto indexs=selectionModel->selectedIndexes();//通过选择模型可以获取选择的多个单元格的模型索引 for(int i=0;i<indexs.count();i++) { QStandardItem * item=model->itemFromIndex(indexs[i]);//通过模型索引获取项 item->setTextAlignment(Qt::AlignVCenter|Qt::AlignLeft); } }
4.粗体
粗体action是复选框,用这个信号
void MainWindow::on_actionBold_triggered(bool checked) { if(!selectionModel->hasSelection())//没有选择就直接退出 { return; } auto indexs=selectionModel->selectedIndexes();//通过选择模型可以获取选择的多个单元格的模型索引 for(int i=0;i<indexs.count();i++) { QStandardItem * item=model->itemFromIndex(indexs[i]);//通过模型索引获取项 QFont font=item->font(); font.setBold(true); item->setFont(font); } }
运行结果:
五.模型的信号
1.解决粗体action问题
但是现在有一个问题,那就是我点粗体action之后,他不会变化,当我选择另外一个单元格的时候,他还是一直选中的,明显不合理,我明明就没有粗体。
就像这样,不是粗体但是复选框也是打开的。
这个时候我们就需要动态的来控制粗体按钮的开与关了。
当我们选择另一个单元格的时候,选择模型就可以发出信号,所以我们来使用选择模型的信号。
因为模型不是ui界面所以只能我们手动关联,和写槽函数。
选信号可以到选择模型里面去找。
槽函数:
void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
信号槽关联:
connect(selectionModel,SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this,SLOT(on_currentChanged(const QModelIndex &, const QModelIndex &)));
槽函数的实现:
void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { if(current.isValid())//如果当前点击的单元格是有效的。 { auto item=model->itemFromIndex(current);//通过当前模型索引获取单元格 ui->actionBold->setChecked(item->font().bold());//如果是粗体就打开,不是就关闭 } }
就很nice可以去玩玩。
2.状态栏显示信息
statusBar()->addWidget(labelInfo);//状态栏添加一个标签
还是在选择变化的槽函数里面
void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { if(current.isValid())//如果当前点击的单元格是有效的。 { auto item=model->itemFromIndex(current);//通过当前模型索引获取单元格 ui->actionBold->setChecked(item->font().bold());//如果是粗体就打开,不是就关闭 labelInfo->setText(QString::asprintf("单元格信息:行:%d 列:%d",current.row(),current.column())+" 内容:"+item->text()); } }
运行结果:
六.总结
对于这些功能的处理,拿到item,可以通过行和列坐标,可以通过模型索引。对于上节的内容,我们主要是设置item。所以对于我们学过的东西一定要找相似点,要总结一下。
好了,标准项模型和选择模型就讲到这里了。
慌了,你就慢下来,还慌,你就停下来!