网站建设工作分解结构词典,在哪里可以建设网站,微信营销系统平台,外贸网站推广中山文章目录 1. 实例功能概述2. Qt预定义编码文件的读写2.1 保存为stm文件2.2 stm文件格式2.3 读取stm文件 3. 标准编码文件的读写3.1 保存为dat文件3.2 dat文件格式3.3 读取dat文件 4. 框架及源码4.1 可视化UI设计4.2 mainwindow.cpp 1. 实例功能概述
除了文本文件之外#xff… 文章目录 1. 实例功能概述2. Qt预定义编码文件的读写2.1 保存为stm文件2.2 stm文件格式2.3 读取stm文件 3. 标准编码文件的读写3.1 保存为dat文件3.2 dat文件格式3.3 读取dat文件 4. 框架及源码4.1 可视化UI设计4.2 mainwindow.cpp 1. 实例功能概述
除了文本文件之外其他需要按照一定的格式定义读写的文件都称为二进制文件。每种格式的二进制文件都有自己的格式定义写入数据时按照一定的顺序写入读出时也按照相应的顺序读出。例如地球物理中常用的 SEG-Y 格式文件必须按照其标准格式要求写入数据才符合这种文件的格式规范读取数据时也需要按照格式定义来读出。 Qt 使用 QFile 和QDataStream 进行二进制数据文件的读写。QFile 负责文件的10 设备接口即与文件的物理交互QDataStream 以数据流的方式读取文件内容或写入文件内容。
本节以实例 samp7_2 演示二进制文件的读写图7-2 是程序运行的界面。 实例以表格形式编辑一个数据表采用 Model/View 结构编辑后的数据保存为二进制文件这与第 5.4 节的实例用纯文本文件存储数据不同。
根据 QDataStream 保存文件时使用的数据编码的方式不同可以保存为两种文件。
(1)用Qt预定义编码保存各种类型数据的文件定义文件后缀为“.stm”。Qt 预定义编码是指在写入某个类型数据如整形数、字符串等到文件流时使用 Qt 预定义的编码。可以将这种 Qt 预定义数据格式编码类比于 HTML 的标记符Qt 写入某种类型数据时用了 Qt 预定义的标记符读出数据时根据标记符读出数据。使用 Qt 预定义编码保存的流文件某些字节是 QDataStream 自己写入的我们并不完全知道文件内每个字节的意义但是用 QDataStream 可以读出相应的数据。
(2)标准编码数据文件定义文件后缀为“.dat”。在将数据写到文件时完全使用数据的二进制原始内容每个字节都有具体的定义在读出数据时只需根据每个字节的定义读出数据即可。
实例samp7_2具有如下功能 可以在表格内编辑数据同样的表格数据内容可以保存为两种格式的文件Qt 预定义编码文件(stm 文件)和标准编码文件 (dat 文件) 界面上的表格数据可以修改可以添加行、插入行、删除行 可以读取 stm 文件或 dat 文件虽然文件格式不一样但对相同的界面数据表存储的文件的实质内容是一样的。
实例samp7_2的主窗口使用了 Model/View 结构、标准项数据模型 QStandardItemModel和选择模型QItemSelectionModel界面上使用了QTableView 组件还有代理组件。这些涉及 Model/View的设计可参考第 5.4 节和 5.5 节这些设计在前述章节里已经介绍过不是本节的重点不再详述。
为便于理解后面的程序这里给出主窗口 MainWindow 类中自定义的一些变量和函数具体如下(忽略了自动生成的一些定义):
//用于状态栏的信息显示QLabel *LabCellPos; //当前单元格行列号QLabel *LabCellText; //当前单元格内容QWIntSpinDelegate intSpinDelegate; //整型数QWFloatSpinDelegate floatSpinDelegate; //浮点数QWComboBoxDelegate comboBoxDelegate; //列表选择QStandardItemModel *theModel;//数据模型QItemSelectionModel *theSelection;//Item选择模型void resetTable(int aRowCount); //表格复位设定行数bool saveDataAsStream(QString aFileName);//将数据保存为数据流文件bool openDataAsStream(QString aFileName);//读取数据流文件bool saveBinaryFile(QString aFileName);//保存为二进制文件bool openBinaryFile(QString aFileName);//打开二进制文件2. Qt预定义编码文件的读写
2.1 保存为stm文件
先看文件保存功能因为从文件保存功能的代码可以看出文件内数据的存储顺序。在图 7-2的窗口上编辑表格的数据后单击工具栏上的“保存 st 文件”可以使用 Qt 预定义编码方式保存文件。此按钮的响应代码如下:
void MainWindow::on_actSave_triggered()
{ //以Qt预定义编码保存数据文件QString curPathQDir::currentPath();QString aFileNameQFileDialog::getSaveFileName(this,tr(选择保存文件),curPath,Qt预定义编码数据文件(*.stm));if (aFileName.isEmpty())return; //if (saveDataAsStream(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经成功保存!);
}bool MainWindow::saveDataAsStream(QString aFileName)
{//将模型数据保存为Qt预定义编码的数据文件QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::WriteOnly | QIODevice::Truncate)))return false;QDataStream aStream(aFile);aStream.setVersion(QDataStream::Qt_5_9); //设置版本号写入和读取的版本号要兼容qint16 rowCounttheModel-rowCount(); //数据模型行数qint16 colCounttheModel-columnCount(); //数据模型列数aStreamrowCount; //写入文件流行数aStreamcolCount;//写入文件流列数//获取表头文字for (int i0;itheModel-columnCount();i){QString strtheModel-horizontalHeaderItem(i)-text();//获取表头文字aStreamstr; //字符串写入文件流Qt预定义编码方式}//获取数据区的数据for (int i0;itheModel-rowCount();i){QStandardItem* aItemtheModel-item(i,0); //测深qint16 ceShenaItem-data(Qt::DisplayRole).toInt();aStreamceShen;// 写入文件流qint16aItemtheModel-item(i,1); //垂深qreal chuiShenaItem-data(Qt::DisplayRole).toFloat();aStreamchuiShen;//写入文件流 qrealaItemtheModel-item(i,2); //方位qreal fangWeiaItem-data(Qt::DisplayRole).toFloat();aStreamfangWei;//写入文件流 qrealaItemtheModel-item(i,3); //位移qreal weiYiaItem-data(Qt::DisplayRole).toFloat();aStreamweiYi;//写入文件流 qrealaItemtheModel-item(i,4); //固井质量QString zhiLiangaItem-data(Qt::DisplayRole).toString();aStreamzhiLiang;// 写入文件流字符串aItemtheModel-item(i,5); //测井bool quYang(aItem-checkState()Qt::Checked);aStreamquYang;// 写入文件流bool型}aFile.close();return true;
}自定义函数 saveDataAsStream()将表格的数据模型 theModel 的数据保存为一个 stm 文件。代码首先是创建 QFile 对象aFile 打开文件然后创建 DataStream 对象aStream 与 QFile 对象关联。
在开始写数据流之前为QDataStream 对象 aStream 设置版本号即调用 setVersion()函数并传递一个QDataStream::Version 枚举类型的值。
aStream.setVersion(QDataStream::Qt_5_9); //设置版本号写入和读取的版本号要兼容
这表示aStream将以QDataStream::Qt_5_9版本的预定义类型写文件流
注意以 Qt 的预定义类型编码保存的文件需要指定流版本号因为每个版本的 Qt 对数据类型的编码可能有差别需要保证写文件和读文件的流版本是兼容的。
接下来就是按照需要保存数据的顺序写入文件流。例如在文件开始先写入行数和列数两个 qint16 的整数。因为行数和列数关系到后面的数据是如何组织的因此在读取文件数据时首先读取这两个整数然后根据数据存储方式的约定就知道后续数据该如何读取了。向文件写入数据时直接用流的输入操作如: aStreamrowCount; //读取行数aStreamcolCount; //列数在读取各列的表头字符串之后将其写入数据流。然后逐行扫描表格的数据模型将每一行的列数据写入数据流。 数据流写入数据时都使用运算符“”不论写的是 qint16、qreal还是字符串。除了可以写入基本的数据类型外QDataStream 流操作还可以写入很多其他类型的数据如QBrush、QColor、QImage、QIcon 等这些称为可序列化的数据类型(Serializing Qt Data Types)。 QDataStream 以流操作写入这些数据时我们并不知道文件里每个字节是如何存储的但是知道数据写入的顺序以及每次写入数据的类型。在文件数据读出时只需按照顺序和类型对应读出即可。
2.2 stm文件格式
根据 saveDataAsStream()函数的代码可知 Qt 预定义编码保存的 stm 文件的格式如表 7-1所示。 从表 7-1 中可以知道 stm 文件的数据存储顺序和类型但是并不知道 qit16 类型的数据存储为几个字节以及 QString 类型的数据是如何定义长度和字符内容的其实也不需要知道这些具体的存储方式在从文件读出时只需按照表 7-1 的顺序和类型读出数据即可。
2.3 读取stm文件
下面是工具栏按钮“打开 stm 文件”的响应代码及相关函数代码选择需要打开的 stm 文件后主要是调用自定义函数 openDataAsStream()将其打开。
void MainWindow::on_actOpen_triggered()
{QString curPathQDir::currentPath();
//调用打开文件对话框打开一个文件QString aFileNameQFileDialog::getOpenFileName(this,tr(打开一个文件),curPath,流数据文件(*.stm));if (aFileName.isEmpty())return; //if (openDataAsStream(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经打开!);
}bool MainWindow::openDataAsStream(QString aFileName)
{ //从Qt预定义流文件读入数据QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::ReadOnly)))return false;QDataStream aStream(aFile); //用文本流读取文件aStream.setVersion(QDataStream::Qt_5_9); //设置流文件版本号qint16 rowCount,colCount;aStreamrowCount; //读取行数aStreamcolCount; //列数this-resetTable(rowCount); //表格复位//获取表头文字QString str;for (int i0;icolCount;i)aStreamstr; //读取表头字符串//获取数据区文字qint16 ceShen;qreal chuiShen;qreal fangWei;qreal weiYi;QString zhiLiang;bool quYang;QStandardItem *aItem;QModelIndex index;for (int i0;irowCount;i){aStreamceShen;//读取测深, qint16indextheModel-index(i,0);aItemtheModel-itemFromIndex(index);aItem-setData(ceShen,Qt::DisplayRole);aStreamchuiShen;//垂深,qrealindextheModel-index(i,1);aItemtheModel-itemFromIndex(index);aItem-setData(chuiShen,Qt::DisplayRole);aStreamfangWei;//方位,qrealindextheModel-index(i,2);aItemtheModel-itemFromIndex(index);aItem-setData(fangWei,Qt::DisplayRole);aStreamweiYi;//位移,qrealindextheModel-index(i,3);aItemtheModel-itemFromIndex(index);aItem-setData(weiYi,Qt::DisplayRole);aStreamzhiLiang;//固井质量,QStringindextheModel-index(i,4);aItemtheModel-itemFromIndex(index);aItem-setData(zhiLiang,Qt::DisplayRole);aStreamquYang;//boolindextheModel-index(i,5);aItemtheModel-itemFromIndex(index);if (quYang)aItem-setCheckState(Qt::Checked);elseaItem-setCheckState(Qt::Unchecked);}aFile.close();return true;
}读取 stm 文件的数据之前也必须设置 QDataStream 的流版本号应该等于或高于数据保存时的流版本号。
然后就是按照表 7-1 所示的写入数据时的顺序和类型相应地读出每个数据。文件里最早的两个数据是表格的行数和列数读出这两个数据就能知道数据的行数和列数并调用自定义函数 resetTable()给数据模型复位并设置其行数。 然后将保存的每行数据读入到数据模型的每个项中,这样窗口上的 QTableView 组件就可以显示数据了。
使用QDataStream 的流操作方式读写文件的特点如下。 读写操作都比较方便支持读写各种数据类型包括 Qt 的一些类还可以为流数据读写扩展自定义的数据类型。读写某种类型的数据时只要是流支持即可而在文件内部是如何存储的用户无需关心由 Qt 预定义。 写文件和读文件时必须保证使用的流版本兼容即流的版本号相同或读取文件的流版本号高于写文件时的流版本号。这是因为在不同的流版本中流支持的数据类型的读写方式可能有所改变必须保证读写版本的兼容。 用这种方式保存文件时写入数据采用 Qt 预定义的编码即写入文件的二进制编码是由Qt预定义的写多少个字节、字节是什么样的顺序用户是不知道的。如果是由QDataStream读取数据只需按类型读出即可。但是如果由这种方法创建的文件是用于交换的需要用其他的编程语言(如 Matlab) 来读取文件内容则存在问题了。因为其他语言并没有与Qt 的流写入完全一致的流读出功能例如其他语言并不知道 Qt 保存的 QString 或 QFont的内容是如何组织的。
3. 标准编码文件的读写
3.1 保存为dat文件
前面是采用 Qt 预定义编码读写 stm 文件这种方法使用简单但是文件的格式不完全透明不能创建用于交换的通用格式文件。 创建通用格式文件(即文件格式完全透明每个字节都有具体的定义如 SEG-Y 文件)的方法是以标准编码方式创建文件使文件的每个字节都有具体的定义。用户在读取这种文件时按照文件格式定义读取出每个字节数据并做解析即可不管使用什么编程语言都可以编写读写文件的程序。 主窗口工具栏上的“保存 dat 文件”按将表格中的数据保存为标准编码的文件文件后缀是“.dat”。保存 dat 文件的代码是:
void MainWindow::on_actSaveBin_triggered()
{//保存二进制文件QString curPathQDir::currentPath();//调用打开文件对话框选择一个文件QString aFileNameQFileDialog::getSaveFileName(this,tr(选择保存文件),curPath,二进制数据文件(*.dat));if (aFileName.isEmpty())return; //if (saveBinaryFile(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经成功保存!);
}bool MainWindow::saveBinaryFile(QString aFileName)
{ //保存为纯二进制文件QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::WriteOnly)))return false;QDataStream aStream(aFile); //用文本流读取文件
// aStream.setVersion(QDataStream::Qt_5_9); //无需设置数据流的版本aStream.setByteOrder(QDataStream::LittleEndian);//windows平台
// aStream.setByteOrder(QDataStream::BigEndian);//QDataStream::LittleEndianqint16 rowCounttheModel-rowCount();qint16 colCounttheModel-columnCount();aStream.writeRawData((char *)rowCount,sizeof(qint16)); //写入文件流aStream.writeRawData((char *)colCount,sizeof(qint16));//写入文件流//获取表头文字QByteArray btArray;QStandardItem *aItem;for (int i0;itheModel-columnCount();i){aItemtheModel-horizontalHeaderItem(i); //获取表头itemQString straItem-text(); //获取表头文字btArraystr.toUtf8(); //转换为字符数组aStream.writeBytes(btArray,btArray.length()); //写入文件流,长度uint型然后是字符串内容}//获取数据区文字qint8 yes1,no0; //分别代表逻辑值 true和falsefor (int i0;itheModel-rowCount();i){aItemtheModel-item(i,0); //测深qint16 ceShenaItem-data(Qt::DisplayRole).toInt();//qint16类型aStream.writeRawData((char *)ceShen,sizeof(qint16));//写入文件流aItemtheModel-item(i,1); //垂深qreal chuiShenaItem-data(Qt::DisplayRole).toFloat();//qreal 类型aStream.writeRawData((char *)chuiShen,sizeof(qreal));//写入文件流aItemtheModel-item(i,2); //方位qreal fangWeiaItem-data(Qt::DisplayRole).toFloat();aStream.writeRawData((char *)fangWei,sizeof(qreal));aItemtheModel-item(i,3); //位移qreal weiYiaItem-data(Qt::DisplayRole).toFloat();aStream.writeRawData((char *)weiYi,sizeof(qreal));aItemtheModel-item(i,4); //固井质量QString zhiLiangaItem-data(Qt::DisplayRole).toString();btArrayzhiLiang.toUtf8();aStream.writeBytes(btArray,btArray.length()); //写入长度,uint然后是字符串
// aStream.writeRawData(btArray,btArray.length());//对于字符串应使用writeBytes()函数aItemtheModel-item(i,5); //测井取样bool quYang(aItem-checkState()Qt::Checked); //true or falseif (quYang)aStream.writeRawData((char *)yes,sizeof(qint8));elseaStream.writeRawData((char *)no,sizeof(qint8));}aFile.close();return true;
}字节序
在保存为标准编码的二进制文件时无须指定 QDataStream 的版本因为不会用到 Qt的类型预定义编码文件的每个字节的意义都是用户自己定义的。但是如有必要需要为文件指定字节顺序如
aStream.setByteOrder(QDataStream::LittleEndian);//windows平台
字节顺序分为大端字节序和小端字节序小端字节序指低字节数据存放在内存低地址处高字节数据存放在内存高地址处大端字节序则相反。
基于X86平台的计算机是小端字节序的所以 Windows 系统是小端字节序而有的嵌入式平台或工作站平台则是大端字节序的。读取一个文件时首先需要知道它是以什么字节序存储的这样才可以正确的读出。
setByteOrder()函数的参数是 QDataStream::ByteOrder 枚举类型常量QDataStream::BigEndian 是大端字节序QDataStream::LittleEndian 是小端字节序。
writeRawData()函数
QdataStream 采用函数 writeRawData()将数据写入数据流在保存qint8、qint16、qreal等类型的数据时都使用这个函数其函数原型是:
int QDataStream::writeRawData(const char *s, int len)
其中参数s是一个指向字节型数据的指针len 是字节数据的长度。调用 writeRawData()函数将会向文件流连续写入len 个字节的数据这些字节数据保存在指针 s 指向的起始地址里。例如将qint16类型变量rowCount 写入文件的语句是: qint16 rowCounttheModel-rowCount();qint16 colCounttheModel-columnCount();writeBytes()函数
在将字符串数据写入文件时使用的是 writeBytes()函数而不是 writeRawData()。下面是writeBytes()函数的原型定义:
QDataStream QDataStream::writeBytes(const char *s, uint len)
其中参数s 是一个指向字节型数据的指针len 是字节数据的长度。writeBytes()在写入数据时,会先将 len 作为一个 quint32 类型写入数据流然后再写入 len 个从指针s 获取的数据。
writeBytes()适合于写入字符串数据因为在写入字符串之前要先写入字符串的长度这样在读取文件时就能知道字符串的长度以便正确读出字符串。
例如下面的代码将字符串“Depth”写入文件流
QString strDepth”;
QByteArray btArraystr.toUtf8();
aStream.writeBytes(btArray,btArray.length());文件中实际保存的内容见表 7-2。前 4 个字节是 quint32 类型的整数表示保存数据的字节个数这里是 5表示后续有5 个字节数据。从第 5 字节开始是保存的字符串”Depth”的每个字符的ASCII码。 由于写入文件的字符串的长度一般是不固定的因此如果以 writeRawData()函数写入文件只会写入字符串的内容而没有表示字符串的长度。在文件读出时如果不已知字符串长度则难以正确读出字符串内容。而 writeBytes()函数首先写入了字符串的长度在读取文件时先从前四个字节读出字符串长度知道数据有多少个字节就可以正确读出了。
QDataStream 提供了与 writeBytes()对应的函数 readBytes()它可以自动读取长度和内容适用于字符串数据的读取。
3.2 dat文件格式
用 saveBinaryFile()函数保存数据为标准编码二进制文件文件后缀为“.dat”。根据saveBinaryFile()函数的内容dat 文件的格式见表 7-3。 在表 7-3 中可以看到文件内的每个字节都是有具体定义的这样无论用什么语言编写一个文件读取的程序只要按照这个格式来读取都可以正确读出文件内容。
dat 文件的数据是否是按照表 7-3 所示的顺序存储的呢?可以创建一个简单的数据表格保存为 dat 后缀的文件然后用显示文件二进制内容的软件来查看如 ltraEdit 或 WinHex这些软件在分析文件格式编写文件读写程序时特别有用。
3.3 读取dat文件
对于保存的 dat 文件主窗口工具栏上的“打开 dat 文件”按钮可以打开保存的 dat 文件下面是打开 dat 文件的函数 openBinaryFile()的代码。
bool MainWindow::openBinaryFile(QString aFileName)
{//打开二进制文件QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::ReadOnly)))return false;QDataStream aStream(aFile); //用文本流读取文件
// aStream.setVersion(QDataStream::Qt_5_9); //设置数据流的版本aStream.setByteOrder(QDataStream::LittleEndian);
// aStream.setByteOrder(QDataStream::BigEndian);qint16 rowCount,colCount;aStream.readRawData((char *)rowCount, sizeof(qint16));aStream.readRawData((char *)colCount, sizeof(qint16));this-resetTable(rowCount);//获取表头文字,但是并不利用char *buf;uint strLen; //也就是 quint32for (int i0;icolCount;i){aStream.readBytes(buf,strLen);//同时读取字符串长度和字符串内容QString strQString::fromLocal8Bit(buf,strLen); //可处理汉字}//获取数据区数据QStandardItem *aItem;qint16 ceShen;qreal chuiShen;qreal fangWei;qreal weiYi;QString zhiLiang;qint8 quYang; //分别代表逻辑值 true和falseQModelIndex index;for (int i0;irowCount;i){aStream.readRawData((char *)ceShen, sizeof(qint16)); //测深indextheModel-index(i,0);aItemtheModel-itemFromIndex(index);aItem-setData(ceShen,Qt::DisplayRole);aStream.readRawData((char *)chuiShen, sizeof(qreal)); //垂深indextheModel-index(i,1);aItemtheModel-itemFromIndex(index);aItem-setData(chuiShen,Qt::DisplayRole);aStream.readRawData((char *)fangWei, sizeof(qreal)); //方位indextheModel-index(i,2);aItemtheModel-itemFromIndex(index);aItem-setData(fangWei,Qt::DisplayRole);aStream.readRawData((char *)weiYi, sizeof(qreal)); //位移indextheModel-index(i,3);aItemtheModel-itemFromIndex(index);aItem-setData(weiYi,Qt::DisplayRole);aStream.readBytes(buf,strLen);//固井质量zhiLiangQString::fromLocal8Bit(buf,strLen);indextheModel-index(i,4);aItemtheModel-itemFromIndex(index);aItem-setData(zhiLiang,Qt::DisplayRole);aStream.readRawData((char *)quYang, sizeof(qint8)); //测井取样indextheModel-index(i,5);aItemtheModel-itemFromIndex(index);if (quYang1)aItem-setCheckState(Qt::Checked);elseaItem-setCheckState(Qt::Unchecked);}aFile.close();return true;
}字节序
在流创建后需要用 setByteOrder()函数指定字节序并且与写入文件时用的字节序一致。
readRawData()函数
在读取基本类型数据时使用QDataStream 的readRawData()函数该函数原型为:
int QDataStream::readRawData(char *s, int len)
它会读取 len 个字节的数据并且保存到指针 s 指向的存储区。例如: qint16 rowCount,colCount;aStream.readRawData((char *)rowCount, sizeof(qint16));aStream.readRawData((char *)colCount, sizeof(qint16));readBytes()函数
读取字符串时使用readBytes()函数它是与writeBytes()功能对应的函数其函数原型为:
QDataStream QDataStream::readBytes(char *s, uint l)
对应表格 7-2使用readBytes()函数时会先自动读取前 4 个字节数据作为quint32 的数据并赋值给 len 参数因为 len 是以引用方式传递的参数所以len 返回读取的数据的字节数。然后根据 len 的大小读取相应字节的数据存储到指针 s 指向的存储区。
4. 框架及源码
4.1 可视化UI设计 4.2 mainwindow.cpp
#include mainwindow.h
#include ui_mainwindow.h#include QFileDialog
#include QDataStream
#include QMessageBoxvoid MainWindow::resetTable(int aRowCount)
{ //表格复位先删除所有行再设置新的行数表头不变
// QStringList headerList;
// headerList测深(m)垂深(m)方位(°)总位移(m)固井质量测井取样;
// theModel-setHorizontalHeaderLabels(headerList); //设置表头文字theModel-removeRows(0,theModel-rowCount()); //删除所有行theModel-setRowCount(aRowCount);//设置新的行数QString strtheModel-headerData(theModel-columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();for (int i0;itheModel-rowCount();i){ //设置最后一列QModelIndex indextheModel-index(i,FixedColumnCount-1); //获取模型索引QStandardItem* aItemtheModel-itemFromIndex(index); //获取itemaItem-setCheckable(true);aItem-setData(str,Qt::DisplayRole);aItem-setEditable(false); //不可编辑}
}bool MainWindow::saveDataAsStream(QString aFileName)
{//将模型数据保存为Qt预定义编码的数据文件QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::WriteOnly | QIODevice::Truncate)))return false;QDataStream aStream(aFile);aStream.setVersion(QDataStream::Qt_5_9); //设置版本号写入和读取的版本号要兼容qint16 rowCounttheModel-rowCount(); //数据模型行数qint16 colCounttheModel-columnCount(); //数据模型列数aStreamrowCount; //写入文件流行数aStreamcolCount;//写入文件流列数//获取表头文字for (int i0;itheModel-columnCount();i){QString strtheModel-horizontalHeaderItem(i)-text();//获取表头文字aStreamstr; //字符串写入文件流Qt预定义编码方式}//获取数据区的数据for (int i0;itheModel-rowCount();i){QStandardItem* aItemtheModel-item(i,0); //测深qint16 ceShenaItem-data(Qt::DisplayRole).toInt();aStreamceShen;// 写入文件流qint16aItemtheModel-item(i,1); //垂深qreal chuiShenaItem-data(Qt::DisplayRole).toFloat();aStreamchuiShen;//写入文件流 qrealaItemtheModel-item(i,2); //方位qreal fangWeiaItem-data(Qt::DisplayRole).toFloat();aStreamfangWei;//写入文件流 qrealaItemtheModel-item(i,3); //位移qreal weiYiaItem-data(Qt::DisplayRole).toFloat();aStreamweiYi;//写入文件流 qrealaItemtheModel-item(i,4); //固井质量QString zhiLiangaItem-data(Qt::DisplayRole).toString();aStreamzhiLiang;// 写入文件流字符串aItemtheModel-item(i,5); //测井bool quYang(aItem-checkState()Qt::Checked);aStreamquYang;// 写入文件流bool型}aFile.close();return true;
}bool MainWindow::openDataAsStream(QString aFileName)
{ //从Qt预定义流文件读入数据QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::ReadOnly)))return false;QDataStream aStream(aFile); //用文本流读取文件aStream.setVersion(QDataStream::Qt_5_9); //设置流文件版本号qint16 rowCount,colCount;aStreamrowCount; //读取行数aStreamcolCount; //列数this-resetTable(rowCount); //表格复位//获取表头文字QString str;for (int i0;icolCount;i)aStreamstr; //读取表头字符串//获取数据区文字qint16 ceShen;qreal chuiShen;qreal fangWei;qreal weiYi;QString zhiLiang;bool quYang;QStandardItem *aItem;QModelIndex index;for (int i0;irowCount;i){aStreamceShen;//读取测深, qint16indextheModel-index(i,0);aItemtheModel-itemFromIndex(index);aItem-setData(ceShen,Qt::DisplayRole);aStreamchuiShen;//垂深,qrealindextheModel-index(i,1);aItemtheModel-itemFromIndex(index);aItem-setData(chuiShen,Qt::DisplayRole);aStreamfangWei;//方位,qrealindextheModel-index(i,2);aItemtheModel-itemFromIndex(index);aItem-setData(fangWei,Qt::DisplayRole);aStreamweiYi;//位移,qrealindextheModel-index(i,3);aItemtheModel-itemFromIndex(index);aItem-setData(weiYi,Qt::DisplayRole);aStreamzhiLiang;//固井质量,QStringindextheModel-index(i,4);aItemtheModel-itemFromIndex(index);aItem-setData(zhiLiang,Qt::DisplayRole);aStreamquYang;//boolindextheModel-index(i,5);aItemtheModel-itemFromIndex(index);if (quYang)aItem-setCheckState(Qt::Checked);elseaItem-setCheckState(Qt::Unchecked);}aFile.close();return true;
}bool MainWindow::saveBinaryFile(QString aFileName)
{ //保存为纯二进制文件QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::WriteOnly)))return false;QDataStream aStream(aFile); //用文本流读取文件
// aStream.setVersion(QDataStream::Qt_5_9); //无需设置数据流的版本aStream.setByteOrder(QDataStream::LittleEndian);//windows平台
// aStream.setByteOrder(QDataStream::BigEndian);//QDataStream::LittleEndianqint16 rowCounttheModel-rowCount();qint16 colCounttheModel-columnCount();aStream.writeRawData((char *)rowCount,sizeof(qint16)); //写入文件流aStream.writeRawData((char *)colCount,sizeof(qint16));//写入文件流//获取表头文字QByteArray btArray;QStandardItem *aItem;for (int i0;itheModel-columnCount();i){aItemtheModel-horizontalHeaderItem(i); //获取表头itemQString straItem-text(); //获取表头文字btArraystr.toUtf8(); //转换为字符数组aStream.writeBytes(btArray,btArray.length()); //写入文件流,长度uint型然后是字符串内容}//获取数据区文字qint8 yes1,no0; //分别代表逻辑值 true和falsefor (int i0;itheModel-rowCount();i){aItemtheModel-item(i,0); //测深qint16 ceShenaItem-data(Qt::DisplayRole).toInt();//qint16类型aStream.writeRawData((char *)ceShen,sizeof(qint16));//写入文件流aItemtheModel-item(i,1); //垂深qreal chuiShenaItem-data(Qt::DisplayRole).toFloat();//qreal 类型aStream.writeRawData((char *)chuiShen,sizeof(qreal));//写入文件流aItemtheModel-item(i,2); //方位qreal fangWeiaItem-data(Qt::DisplayRole).toFloat();aStream.writeRawData((char *)fangWei,sizeof(qreal));aItemtheModel-item(i,3); //位移qreal weiYiaItem-data(Qt::DisplayRole).toFloat();aStream.writeRawData((char *)weiYi,sizeof(qreal));aItemtheModel-item(i,4); //固井质量QString zhiLiangaItem-data(Qt::DisplayRole).toString();btArrayzhiLiang.toUtf8();aStream.writeBytes(btArray,btArray.length()); //写入长度,uint然后是字符串
// aStream.writeRawData(btArray,btArray.length());//对于字符串应使用writeBytes()函数aItemtheModel-item(i,5); //测井取样bool quYang(aItem-checkState()Qt::Checked); //true or falseif (quYang)aStream.writeRawData((char *)yes,sizeof(qint8));elseaStream.writeRawData((char *)no,sizeof(qint8));}aFile.close();return true;
}bool MainWindow::openBinaryFile(QString aFileName)
{//打开二进制文件QFile aFile(aFileName); //以文件方式读出if (!(aFile.open(QIODevice::ReadOnly)))return false;QDataStream aStream(aFile); //用文本流读取文件
// aStream.setVersion(QDataStream::Qt_5_9); //设置数据流的版本aStream.setByteOrder(QDataStream::LittleEndian);
// aStream.setByteOrder(QDataStream::BigEndian);qint16 rowCount,colCount;aStream.readRawData((char *)rowCount, sizeof(qint16));aStream.readRawData((char *)colCount, sizeof(qint16));this-resetTable(rowCount);//获取表头文字,但是并不利用char *buf;uint strLen; //也就是 quint32for (int i0;icolCount;i){aStream.readBytes(buf,strLen);//同时读取字符串长度和字符串内容QString strQString::fromLocal8Bit(buf,strLen); //可处理汉字}//获取数据区数据QStandardItem *aItem;qint16 ceShen;qreal chuiShen;qreal fangWei;qreal weiYi;QString zhiLiang;qint8 quYang; //分别代表逻辑值 true和falseQModelIndex index;for (int i0;irowCount;i){aStream.readRawData((char *)ceShen, sizeof(qint16)); //测深indextheModel-index(i,0);aItemtheModel-itemFromIndex(index);aItem-setData(ceShen,Qt::DisplayRole);aStream.readRawData((char *)chuiShen, sizeof(qreal)); //垂深indextheModel-index(i,1);aItemtheModel-itemFromIndex(index);aItem-setData(chuiShen,Qt::DisplayRole);aStream.readRawData((char *)fangWei, sizeof(qreal)); //方位indextheModel-index(i,2);aItemtheModel-itemFromIndex(index);aItem-setData(fangWei,Qt::DisplayRole);aStream.readRawData((char *)weiYi, sizeof(qreal)); //位移indextheModel-index(i,3);aItemtheModel-itemFromIndex(index);aItem-setData(weiYi,Qt::DisplayRole);aStream.readBytes(buf,strLen);//固井质量zhiLiangQString::fromLocal8Bit(buf,strLen);indextheModel-index(i,4);aItemtheModel-itemFromIndex(index);aItem-setData(zhiLiang,Qt::DisplayRole);aStream.readRawData((char *)quYang, sizeof(qint8)); //测井取样indextheModel-index(i,5);aItemtheModel-itemFromIndex(index);if (quYang1)aItem-setCheckState(Qt::Checked);elseaItem-setCheckState(Qt::Unchecked);}aFile.close();return true;
}MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui-setupUi(this);theModel new QStandardItemModel(5,FixedColumnCount,this); //创建数据模型QStringList headerList;headerListDepthMeasured DepthDirectionOffsetQualitySampled;theModel-setHorizontalHeaderLabels(headerList); //设置表头文字theSelection new QItemSelectionModel(theModel);//Item选择模型connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));//为tableView设置数据模型ui-tableView-setModel(theModel); //设置数据模型ui-tableView-setSelectionModel(theSelection);//设置选择模型//为各列设置自定义代理组件ui-tableView-setItemDelegateForColumn(0,intSpinDelegate); //测深整数ui-tableView-setItemDelegateForColumn(1,floatSpinDelegate); //浮点数ui-tableView-setItemDelegateForColumn(2,floatSpinDelegate); //浮点数ui-tableView-setItemDelegateForColumn(3,floatSpinDelegate); //浮点数ui-tableView-setItemDelegateForColumn(4,comboBoxDelegate); //Combbox选择型resetTable(5); //表格复位setCentralWidget(ui-tabWidget); ////创建状态栏组件LabCellPos new QLabel(当前单元格,this);LabCellPos-setMinimumWidth(180);LabCellPos-setAlignment(Qt::AlignHCenter);LabCellText new QLabel(单元格内容,this);LabCellText-setMinimumWidth(200);ui-statusBar-addWidget(LabCellPos);ui-statusBar-addWidget(LabCellText);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_currentChanged(const QModelIndex current, const QModelIndex previous)
{Q_UNUSED(previous);if (current.isValid()){LabCellPos-setText(QString::asprintf(当前单元格%d行%d列,current.row(),current.column()));QStandardItem *aItem;aItemtheModel-itemFromIndex(current); //从模型索引获得Itemthis-LabCellText-setText(单元格内容aItem-text());QFont fontaItem-font();ui-actFontBold-setChecked(font.bold());}
}void MainWindow::on_actOpen_triggered()
{QString curPathQDir::currentPath();
//调用打开文件对话框打开一个文件QString aFileNameQFileDialog::getOpenFileName(this,tr(打开一个文件),curPath,流数据文件(*.stm));if (aFileName.isEmpty())return; //if (openDataAsStream(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经打开!);
}void MainWindow::on_actAppend_triggered()
{ //添加行QListQStandardItem* aItemList; //容器类QStandardItem *aItem;QString str;for(int i0;iFixedColumnCount-2;i){aItemnew QStandardItem(0); //创建ItemaItemListaItem; //添加到容器}aItemnew QStandardItem(优); //创建ItemaItemListaItem; //添加到容器strtheModel-headerData(theModel-columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();aItemnew QStandardItem(str); //创建ItemaItem-setCheckable(true);aItem-setEditable(false);aItemListaItem; //添加到容器theModel-insertRow(theModel-rowCount(),aItemList); //插入一行需要每个Cell的ItemQModelIndex curIndextheModel-index(theModel-rowCount()-1,0);//创建最后一行的ModelIndextheSelection-clearSelection();theSelection-setCurrentIndex(curIndex,QItemSelectionModel::Select);
}void MainWindow::on_actInsert_triggered()
{//插入行QListQStandardItem* aItemList; //QStandardItem的容器类QStandardItem *aItem;QString str;for(int i0;iFixedColumnCount-2;i){aItemnew QStandardItem(0); //新建一个QStandardItemaItemListaItem;//添加到容器类}aItemnew QStandardItem(优); //新建一个QStandardItemaItemListaItem;//添加到容器类strtheModel-headerData(theModel-columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();aItemnew QStandardItem(str); //创建ItemaItem-setCheckable(true);aItem-setEditable(false);aItemListaItem;//添加到容器类QModelIndex curIndextheSelection-currentIndex();theModel-insertRow(curIndex.row(),aItemList);theSelection-clearSelection();theSelection-setCurrentIndex(curIndex,QItemSelectionModel::Select);
}void MainWindow::on_actDelete_triggered()
{ //删除行QModelIndex curIndextheSelection-currentIndex();if (curIndex.row()theModel-rowCount()-1)//(curIndex.isValid())theModel-removeRow(curIndex.row());else{theModel-removeRow(curIndex.row());theSelection-setCurrentIndex(curIndex,QItemSelectionModel::Select);}
}void MainWindow::on_actSave_triggered()
{ //以Qt预定义编码保存数据文件QString curPathQDir::currentPath();QString aFileNameQFileDialog::getSaveFileName(this,tr(选择保存文件),curPath,Qt预定义编码数据文件(*.stm));if (aFileName.isEmpty())return; //if (saveDataAsStream(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经成功保存!);
}void MainWindow::on_actAlignCenter_triggered()
{if (!theSelection-hasSelection())return;QModelIndexList selectedIndixtheSelection-selectedIndexes();QModelIndex aIndex;QStandardItem *aItem;for (int i0;iselectedIndix.count();i){aIndexselectedIndix.at(i);aItemtheModel-itemFromIndex(aIndex);aItem-setTextAlignment(Qt::AlignHCenter);}
}void MainWindow::on_actFontBold_triggered(bool checked)
{if (!theSelection-hasSelection())return;QModelIndexList selectedIndixtheSelection-selectedIndexes();QModelIndex aIndex;QStandardItem *aItem;QFont font;for (int i0;iselectedIndix.count();i){aIndexselectedIndix.at(i);aItemtheModel-itemFromIndex(aIndex);fontaItem-font();font.setBold(checked);aItem-setFont(font);}}void MainWindow::on_actAlignLeft_triggered()
{if (!theSelection-hasSelection())return;QModelIndexList selectedIndixtheSelection-selectedIndexes();QModelIndex aIndex;QStandardItem *aItem;for (int i0;iselectedIndix.count();i){aIndexselectedIndix.at(i);aItemtheModel-itemFromIndex(aIndex);aItem-setTextAlignment(Qt::AlignLeft);}
}void MainWindow::on_actAlignRight_triggered()
{if (!theSelection-hasSelection())return;QModelIndexList selectedIndixtheSelection-selectedIndexes();QModelIndex aIndex;QStandardItem *aItem;for (int i0;iselectedIndix.count();i){aIndexselectedIndix.at(i);aItemtheModel-itemFromIndex(aIndex);aItem-setTextAlignment(Qt::AlignRight);}
}void MainWindow::on_actTabReset_triggered()
{//表格复位resetTable(10);
}void MainWindow::on_actSaveBin_triggered()
{//保存二进制文件QString curPathQDir::currentPath();//调用打开文件对话框选择一个文件QString aFileNameQFileDialog::getSaveFileName(this,tr(选择保存文件),curPath,二进制数据文件(*.dat));if (aFileName.isEmpty())return; //if (saveBinaryFile(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经成功保存!);
}void MainWindow::on_actOpenBin_triggered()
{//打开二进制文件QString curPathQDir::currentPath();//系统当前目录QString aFileNameQFileDialog::getOpenFileName(this,tr(打开一个文件),curPath,二进制数据文件(*.dat));if (aFileName.isEmpty())return; //if (openBinaryFile(aFileName)) //保存为流数据文件QMessageBox::information(this,提示消息,文件已经打开!);
}