图 1 实例 samp5_3 的运行时界面
图 2 实例中创建的 Action
#define FixedColumnCount 6 //文件固定 6 列 class MainWindow : public QMainWindow { Q_OBJECT private: QLabel *LabCurFile; //当前文件 QLabel *LabCellPos; //当前单元格行列号 QLabel *LabCellText; //当前单元格内容 QStandardItemModel * theModel; //数据模型 QItemSelectionModel *theSelection; //选择模型 void iniModelFromStringList (QStringList&) ; //从 StringList 初始化数据模型 public: explicit MainWindow(QWidget *parent = 0); private slots: //当前选择单元格发生变化 void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous); private: Ui::MainWindow *ui; };这里定义了数据模型变量 theModel,项数据选择模型变量 theSelection。
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui (new Ui::MainWindow) { ui->setupUi(this); setCentralWidget(ui->splitter); theModel = new QStandardltemModel (2, FixedColumnCount, this) ; //数据模型 theSelection = new QItemSelectionModel (theModel) ;//选择模型 connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)), this,SLOT(on_currentChanged(QModelIndex,QModelIndex))); ui->tableView->setModel (theModel) ; //设置数据模型 ui->tableVi.evi-> setSelectionModel(theSelection) ; //设置选择模型 ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems); //创建状态栏组件,代码略 }在构造函数里首先创建数据模型 theModel,创建数据选择模型时需要传递一个数据模型变量作为其参数。这样,数据选择模型 theSelection 就与数据模型 theModel 关联,用于表示 theModel 的项数据选择操作。
ui->tableView->setModel (theModel) ; //设置数据模型
ui->tableView->setSelectionModel (theSelection) ; //设置选择模型
void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { //选择单元格变化时的响应 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()); } }
图 3 纯文本格式的数据文件
void MainWindow::on_actOpen_triggered() { //打开文件 //QString str; QString curPath=QCoreApplication::applicationDirPath(); //获取应用程序的路径 //调用打开文件对话框打开一个文件 QString aFileName=QFileDialog::getOpenFileName(this,"打开一个文件",curPath, "井数据文件(*.txt);;所有文件(*.*)"); if (aFileName.isEmpty()) return; //如果未选择文件,退出 QStringList fFileContent;//文件内容字符串列表 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); //添加到文本框显示 fFileContent.append(str); //添加到 StringList } aFile.close();//关闭文件 this->LabCurFile->setText("当前文件:"+aFileName);//状态栏显示 ui->actAppend->setEnabled(true); //更新Actions的enable属性 ui->actInsert->setEnabled(true); ui->actDelete->setEnabled(true); ui->actSave->setEnabled(true); iniModelFromStringList(fFileContent);//从StringList的内容初始化数据模型 } }这段代码让用户选择所需要打开的数据文本文件,然后用只读和文本格式打开文件,逐行读取其内容,将每行字符串显示到界面上的 plainTextEdit 里,并且添加到一个临时的 QStringList 类型的变量 fFileContent 里。
void MainWindow::iniModelFromStringList(QStringList& aFileContent) { //从一个StringList 获取数据,初始化数据Model int rowCnt=aFileContent.count(); //文本行数,第1行是标题 theModel->setRowCount(rowCnt-1); //实际数据行数 //设置表头 QString header=aFileContent.at(0);//第1行是表头 //一个或多个空格、TAB等分隔符隔开的字符串, 分解为一个StringList QStringList headerList=header.split(QRegExp("\\s+"),QString::SkipEmptyParts); theModel->setHorizontalHeaderLabels(headerList); //设置表头文字 //设置表格数据 QString aText; QStringList tmpList; int j; QStandardItem *aItem; for (int i=1;i<rowCnt;i++) { QString aLineText=aFileContent.at(i); //获取数据区的一行 //一个或多个空格、TAB等分隔符隔开的字符串, 分解为一个StringList QStringList tmpList=aLineText.split(QRegExp("\\s+"),QString::SkipEmptyParts); for (j=0;j<FixedColumnCount-1;j++) //tmpList的行数等于FixedColumnCount, 固定的 { //不包含最后一列 aItem=new QStandardItem(tmpList.at(j));//创建item theModel->setItem(i-1,j,aItem); //为模型的某个行列位置设置Item } aItem=new QStandardItem(headerList.at(j));//最后一列是Checkable,需要设置 //aItem=new QStandardItem();//最后一列是Checkable,设置 aItem->setCheckable(true); //设置为Checkable //aItem->setTextAlignment(Qt::AlignHCenter); if (tmpList.at(j)=="0") aItem->setCheckState(Qt::Unchecked); //根据数据设置check状态 else aItem->setCheckState(Qt::Checked); theModel->setItem(i-1,j,aItem); //为模型的某个行列位置设置Item } }传递来的参数 aFileContent 是文本文件所有行构成的 StringList,文件的每一行是 aFileContent 的一行字符串,第 1 行是表头文字,数据从第 2 行开始。
测深(m) 垂深(m) 方位(°) 总位移(m) 固井质量 测井取样
那么通过上面的 split() 函数操作,得到一个字符串列表 headerList,其内容是:
测深(m)
垂深(m)
方位(°)
总位移(m)
固井质量
测井取样
void MainWindow::on_actAppend_triggered() { //在表格最后添加行 QList<QStandardItem*> aItemList; //容器类 QStandardItem *aItem; for(int i=0;i<FixedColumnCount-1;i++) //不包含最后1列 { aItem=new QStandardItem("0"); //创建Item aItemList<<aItem; //添加到容器 } //获取最后一列的表头文字 QString str=theModel->headerData(theModel->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString(); aItem=new QStandardItem(str); //创建 "测井取样"Item aItem->setCheckable(true); aItemList<<aItem; //添加到容器 theModel->insertRow(theModel->rowCount(),aItemList); //插入一行,需要每个Cell的Item QModelIndex curIndex=theModel->index(theModel->rowCount()-1,0);//创建最后一行的ModelIndex theSelection->clearSelection();//清空选择项 theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);//设置刚插入的行为当前选择行 }使用 QStandardltemModel::insertRow() 函数插入一行,其函数原型是:
void insertRow(int row, const QList<QStandardltem *> fiitems)
其中,row 是一个行号,表示在此行号之前插入一行,若 row 等于或大于总行数,则在最后添加一行。QList<QStandardItem *>&items 是一个 QStandardltem 类型的列表类,需要为插入的一行的每个项数据创建一个 QStandardltem 类型的项,然后传递给 insertRow() 函数。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); } }
void MainWindow::on_actAlignLeft_triggered() { //设置文字居左对齐 if (!theSelection->hasSelection()) return; //获取选择的单元格的模型索引列表,可以是多选 QModelIndexList selectedIndex=theSelection->selectedIndexes(); for (int i=0;i<selectedIndex.count();i++) { QModelIndex aIndex=selectedIndex.at (i) ; //获取一个模型索引 QStandardItem* aItem=theModel->itemFromIndex(aIndex); aItem->setTextAlignment (Qt::AlignLeft) ;//设置文字对齐方式 } }QItemSelectionModel::selectedIndexes() 函数返回选择单元格的模型索引列表,然后通过此列表获取每个选择的单元格的模型索引,再通过模型索引获取其项数据,然后调用 QStandardItem::setTextAlignment() 设置一个项的对齐方式即可。
“居中”和“居右”按钮的代码与此类似。
“粗体”按钮设置单元格的字体是否为粗体,在选择单元格时,actFontBold 的 check 状态根据当前单元格的字体是否为粗体自动更新。actFontBold 的 triggered(bool) 的槽函数代码如下,与设置对齐方式的代码操作方式类似:void MainWindow::on_actFontBold_triggered(bool checked) {//设置字体粗体 if (!theSelection->hasSelection()) return; //获取选择单元格的模型索引列表 QModelIndexList selectedIndex=theSelection->selectedIndexes(); for (int i=0;i<selectedIndex.count();i++) { QModelIndex aIndex=selectedIndex.at(i); //获取一个模型索引 QStandardItem* aItem=theModel->itemFromIndex(aIndex);//获取项数据 QFont font=aItem->font(); //获取字体 font.setBold(checked); //设置字体是否粗体 aItem->setFont(font); //重新设置字体 } }
void MainWindow::on_actSave_triggered() { //保存为文件 QString curPath=QCoreApplication::applicationDirPath(); //获取应用程序的路径 //调用打开文件对话框选择一个文件 QString aFileName=QFileDialog::getSaveFileName(this,tr("选择一个文件"),curPath, "井斜数据文件(*.txt);;所有文件(*.*)"); if (aFileName.isEmpty()) //未选择文件,退出 return; QFile aFile(aFileName); if (!(aFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate))) return; //以读写、覆盖原有内容方式打开文件 QTextStream aStream(&aFile); //用文本流读取文件 QStandardItem *aItem; int i,j; QString str; ui->plainTextEdit->clear(); //获取表头文字 for (i=0;i<theModel->columnCount();i++) { aItem=theModel->horizontalHeaderItem(i); //获取表头的项数据 str=str+aItem->text()+"\t\t"; //以TAB见隔开 } aStream<<str<<"\n"; //文件里需要加入换行符 \n ui->plainTextEdit->appendPlainText(str); //获取数据区文字 for ( i=0;i<theModel->rowCount();i++) { str=""; for( j=0;j<theModel->columnCount()-1;j++) { aItem=theModel->item(i,j); str=str+aItem->text()+QString::asprintf("\t\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"; } }
本文链接:http://task.lmcjl.com/news/17017.html