【Qt QAxObject】使用 QAxObject 高效任意读写 Excel 表

1. 用什么操作 Excel 表

  Qt 的官网库中是不包含 Microsoft Excel 的操作库,关于对 Microsoft Excel 的操作库可选的有很多,包含基于 Windows 系统本身的 ActiveXQt XlsxxlsLibLibXLqtXLSBasicExcelNumber Duck

.xls.xlsx平台
Qt Xlsx✔️✔️✔️跨平台
xls✔️✔️跨平台
libxls✔️✔️跨平台
libXL✔️✔️✔️✔️跨平台
ActiveX✔️✔️✔️✔️Windows原生
qtXLS✔️✔️✔️Windows
BasicExcel✔️✔️✔️Windows
Number Duck✔️✔️✔️WindowsLinux

  本文采用基于 WindowsActiveX 对象,在 Qt 中也就是 QAxObjcet 实现读写 Excel 表。

2. QAxObject 简介

  在介绍 QAxObject 之前,首先简单了解一下 Windows 上的 COM 组件对象模型,COM 是一个独立于平台的分布式面向对象的系统,用于创建可以交互的二进制软件组件。 COMMicrosoftOLE (复合文档的基础技术,) 和 ActiveX (支持 Internet 的组件) 技术。可以使用各种编程语言创建 COM 对象。 面向对象的语言(如 C++)提供了简化 COM 对象的实现的编程机制。 这些对象可以位于单个进程中、其他进程中,甚至在远程计算机上也是如此。

COM 组件模型对象相信介绍可查看:https://download.csdn.net/download/qq_36393978/88268235

  而在 Qt 中的 QAxObject 是对 COM 组件模型对象的封装,QAxObject 派生自QAxBaseQAxBase 提供了一组 API 通过 IUnknown 指针直接访问 COM 对象,具体结构如下图。

在这里插入图片描述

  而在 Windows 上的 Excel 也是一个这样的 COM 对象,因此,可以采用在 Qt 中使用 QAxObjcet 实现对 Excel 的操作,其基本的操作流程如下:

在这里插入图片描述

  如上图描述了 Excel 的层次结构,Excel.Application 对象 → WorkBooks 对象 → WorkBook 对象 → WorkSheet 对象 → Range 对象,1excel 有一个 Application 对象,1Application 对象有多个 Workbook 对象组成,这些 Workbook 对象由 Workbooks 对象统一管理,Workbook 对象下包含若干个 WorkSheet,这些 WorkSheet 对象由 WorkSheets 对象统一管理,WorkSheet 下面的 Range 对象,对应这 WorkSheet 里面的表格单元了。箭头表示获取其子对象,获取方式需调用 querySubObject() 函数获取子对象实例,各个子对象调用 dynamicCall() 函数执行对各自的具体操作。

3. 基本使用方法

3.1. 包含相关文件

  要使用 QAxObject 首先要在 .pro 文件中添加其模块名称 axcontainer,这样工程文件在编译的时候就会加载该模块。

// project.pro
QT       += axcontainer

在头文件中需要包含如下几个头文件

#include <QString>
#include <QFileDialog>
#include <QAxObject>
#include <QVariant>
#include <QVariantList>

3.2. 创建 Excel 进程,获取 Excel 工作簿集

打开文件夹选择 Excel 文件,创建 Excel 进程:

// 打开文件夹
QString strFilePathName = QFileDialog::getOpenFileName(this, QStringLiteral("选择Excel文件"),"", tr("Exel file(*.xls *.xlsx)"));
if(strFilePathName.isNull()) {return ;
}
QAxObject *excel = new QAxObject(this)if (excel->setControl("Excel.Application")) {	// 加载 Microsoft Excel 控件
} else {excel->setControl("ket.Application");  // 加载 WPS Excel 控件
}excel->setProperty("Visible", false);  // 不显示 Excel 窗体
QAxObject* workBooks = excel->querySubObject("WorkBooks");  //获取工作簿集合
workBooks->dynamicCall("Open(const QString&)", strFilePathName); //打开打开已存在的工作簿
QAxObject* workBook = excel->querySubObject("ActiveWorkBook"); //获取当前工作簿

3.3. 获取电子表格集

每个 Excel 工作簿中都可以包含若干电子表格 Sheet

QAxObject* sheets = workBook->querySubObject("Sheets");  //获取工作表集合,Sheets也可换用WorkSheets

获取需要操作的工作表:

QAxObject* sheet = workBook->querySubObject("WorkSheets(int)", 1);//获取工作表集合的工作表1,即sheet1

3.4. 选取需要操作的单元格范围

每页电子表格包含多个单元格,在操作之前需要选取所要操作的单元格范围:
选取当前页面所有已使用单元格:

//获取该sheet的使用范围对象(一般读取 Excel 时会选取全部范围)
QAxObject* usedRange = sheet->querySubObject("UsedRange"); 

选取指定范围的单元格:

//获取 sheet 的指定范围(一般写入数据时,会选取指定范围)
QAxObject* usedRange = sheet->querySubObject("Range(const QString)", "A1:C12");

这里的 A1:C12 则表示选取,AC 列的 1~12 行单元格;若写成 A1:A12 则表示选取,A 列的 1~12 行单元格;当然你也可以写成 A1:A1 则表示只选取 A1 这一个单元格。

选择指定单元格:

//获取 sheet 的指定范围(一般修改数据时,会选取指定单元格)
QAxObject* usedRange = sheet->querySubObject("Range(QVariant,QVariant)", "A6");

这里的 A6,则表示选取 A6 这个单元格。

[注]:获取 UsedRange 操作将会得到一个动态创建 (new) 出来的对象。

3.5. 读取单元格范围内容

  当选取好要操作的单元各范围后,那么这里介绍如何读取选取范围内所有的单元格内容:

QVariant var = usedRange->dynamicCall("Value");
delete usedRange;

  需要注意的是上文代码中除了获取单元格范围 (UsedRange) 操作之外,其余得到的都是该对象的引用,不会占用内存空间,不需要释放,而获取单元格适用范围 (UsedRange) 则得到一个 new 出来新分配的对象,因此在读取或写入操作结束后需要手动释放该对象。

  QVariant 类是一个数据联合体,用来存放读取到的 Excel 数据。而事实上通过调用 dynamicCall("Value") 读到的数据类型是 QList<QList<QVariant>> 类型的,因此要将读到的 var 转换为该类型的数据。

QList<QList<QVariant>> xls_data;QVariantList varRows = var.toList();
if (varRows.isEmpty()) {return;
}const int rowCount = varRows.size();
this->excel.rowCount = rowCount;QVariantList rowData;for (int i = 0; i < rowCount; i++){rowData = varRows[i].toList();if (rowData.count() > this->excel.columnCount) {this->excel.columnCount = rowData.count();}this->xls_data.push_back(rowData);
}

3.6. 将读取到的数据用 QTableView 展示出来

  这里的 TbleView_table1 是在 Forms 中的直接拖拽的 QTableView 控件。

QStandardItemModel *tab_model;
for (int i = 0; i < xls_data.count(); i++) {for (int j = 0; j < xls_data.at(i).count(); j++) {QStandardItem *item = new QStandardItem(QString(xls_data.at(i).at(j).toByteArray()));tab_model->setItem(i, j, item);//delete item;}
}
this->ui->TbleView_table1->setModel(tab_model);

3.7. 向选取的单元格范围写入数据

  想必各位也注意到了,在 Excel 中横轴坐标都是用 A~Z 字母表示为了与纵轴的表示方式区别开来,而我们在操作是常用的则是以数字形式,或者说在设置循环中用数字方式更为方便,因此这里需要实现一个数字转 Excel 横坐标的函数,如下。

QString ExcelProcess::to26AlphabetString(int data)
{QChar ch = (QChar)(data + 0x40);//A对应0x41return QString(ch);
}void ExcelProcess::convertToColName(int data, QString &res)
{Q_ASSERT(data > 0 && data < 65535);int tempData = data / 26;if (tempData > 0) {int mode = data % 26;convertToColName(mode, res);convertToColName(tempData, res);} else {res=(to26AlphabetString(data) + res);}
}

按照指定行、列,一行一行的添加要写入的数据。

QList<QList<QVariant>> data_total;int row = 50 - 30, col = 100 - 10;	// 表示:选取范围为,30~50 行,10~100 列for (int i = 0; i < row; i++) {QList<QVariant> data_row;for (int j = 0; j < col; j++) {data_row.append("ImagineMiracle");}data_total.append(QVariant(data_row));
}
QString row_s, row_e, col_s, col_e, targetRange;
convertToColName(30, row_s);
convertToColName(50, row_e);
convertToColName(10, col_s);
convertToColName(100, col_e);
targetRange= col_s + row_s + ":" + col_e + row_e ;QAxObject* sheet = workBook->querySubObject("WorkSheets(int)", 1);//获取工作表集合的工作表1,即sheet1QAxObject* usedRange = sheet->querySubObject("Range(const QString)", target);
usedRange->setProperty("NumberFormat", "@");    //  设置所有单元格为文本属性
usedRange->dynamicCall("SetValue(const QVariant&", QVariant(data_total));
workBook->dynamicCall("Save()");	// 保存文件
delete usedRange;

3.8. 退出操作

  当执行完所有操作后,需要关闭并退出 Excel,代码如下:

workBook->dynamicCall("Close()"); //关闭工作簿 
excel->dynamicCall("Quit()"); //退出进程delete excel;

4. 示例演示

  下面是笔者写的一个简单的 Excel 表操作的代码,其功能包含
1.打开并读取 Excel 表内容;
2.根据指定表格中数据的范围计算范围内数据量并写入表格;
3.根据数据量计算数据的所在范围。

完成工程下载链接:ExcelProcess.zip

文件列表如下:

在这里插入图片描述

运行效果演示。
在这里插入图片描述

5. 附

这里贴出所有源文件的代码:

5.1. ExcelPrecess.pro

QT       += core gui axcontainergreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++17
RC_ICONS += pic/ExcelTool.ico# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \excelprocess.cppHEADERS += \excelprocess.hFORMS += \excelprocess.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetRESOURCES += \pic.qrc

5.2. excelprocess.h

#ifndef EXCELPROCESS_H
#define EXCELPROCESS_H#include "ui_excelprocess.h"
#include <QMainWindow>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
#include <QLabel>
#include <QFileDialog>
#include <QStandardPaths>
#include <QDebug>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QMovie>
#include <QScopedPointer>
#include <QList>
#include <QAxObject>
#include <QVariant>
#include <QVariantList>
#include <QStandardItemModel>
#include <QThread>
#include <QIcon>QT_BEGIN_NAMESPACE
namespace Ui { class ExcelProcess; }
QT_END_NAMESPACE#define APPNAME ("ExcelTool v1.3.0 build 20230828")typedef struct {QAxObject *excel;QAxObject *workBooks;QAxObject *current_workBook;QAxObject *workSheets;QAxObject *current_workSheet;QAxObject *usedRange;QAxObject *rows;QAxObject *columns;int sheetCount, rowCount, columnCount;}ExcelFile;#define MODECOUNT (3)
static QString excel_mode[MODECOUNT] = {"Null", "Calc", "Range"};typedef struct {int sheet;int col_src;//int col;int col_dest;
} CalcMode;class ExcelProcess : public QMainWindow
{Q_OBJECTprivate slots:void showFiles(void);void on_PBtn_View_clicked();void on_ComBox_Mode_currentIndexChanged(int index);void on_Btn_CalcRun_clicked();void on_LEdit_FilePath_textChanged(const QString &arg1);void on_Btn_RangeRun_clicked();protected:void dragEnterEvent(QDragEnterEvent *event);    // 拖动进入事件void dropEvent(QDropEvent *event);      // 放下事件public:ExcelProcess(QWidget *parent = nullptr);~ExcelProcess();void openExcelFile();void closeExcelFile();void readExcel_OneSheet(int sheet_num);void showOneSheet(int sheet_num);void excelModeDisplay_00(void);void excelModeDisplay_01(void);void excelModeDisplay_02(void);void convertToColName(int data, QString &res);QString to26AlphabetString(int data);void castListListVariant2Variant(const QList<QList<QVariant> > &cells, QVariant &res);private:Ui::ExcelProcess *ui;QString *fileName;QMovie *movie_01;ExcelFile excel;QList<QList<QVariant>> xls_data;    // excel 表数据CalcMode calcMode;QStandardItemModel *tab_model;void initUi(void);void initExcel(void);};
#endif // EXCELPROCESS_H

5.3. excelprocess.cpp

#include "excelprocess.h"
#include "ui_excelprocess.h"void ExcelProcess::showFiles()
{QString str = QFileDialog::getOpenFileName(this, "File Explorer", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),"Excel 文件(*.xls *.xlsx);;All file(*.*)");this->ui->LEdit_FilePath->setText(str.toUtf8());*this->fileName = this->ui->LEdit_FilePath->text();qDebug() << *this->fileName << "\n";return ;
}void ExcelProcess::dragEnterEvent(QDragEnterEvent *event)
{if ((!event->mimeData()->urls()[0].fileName().right(3).compare("xls")) || (!event->mimeData()->urls()[0].fileName().right(4).compare("xlsx"))) {event->acceptProposedAction();} else {event->ignore();}return ;
}void ExcelProcess::dropEvent(QDropEvent *event)
{const QMimeData *qm = event->mimeData();*this->fileName = qm->urls()[0].toLocalFile();  // 获取拖入的文件名this->ui->LEdit_FilePath->clear();this->ui->LEdit_FilePath->setText(*this->fileName);return ;
}ExcelProcess::ExcelProcess(QWidget *parent): QMainWindow(parent), ui(new Ui::ExcelProcess)
{ui->setupUi(this);this->fileName = new QString;this->tab_model = new QStandardItemModel();this->setAcceptDrops(true);     // 设置主界面接收拖动进来的文件this->initUi();this->initExcel();return ;
}ExcelProcess::~ExcelProcess()
{delete ui;delete fileName;this->tab_model->clear();delete this->tab_model;if (this->excel.current_workBook != nullptr) {this->excel.current_workBook->dynamicCall("Save()");this->excel.current_workBook->dynamicCall("Close()"); //关闭文件}if (this->excel.workBooks != nullptr) {this->excel.workBooks->dynamicCall("Close()"); //关闭文件}this->excel.excel->dynamicCall("Quit(void)");   // 退出delete this->excel.workBooks;delete this->excel.excel;return ;
}void ExcelProcess::openExcelFile()
{//this->initExcel();if (this->excel.excel == nullptr) {return ;}this->excel.workBooks->dynamicCall("Open (const QString&)", *this->fileName);this->excel.current_workBook = this->excel.excel->querySubObject("ActiveWorkBook");this->excel.workSheets = this->excel.current_workBook->querySubObject("Sheets");this->excel.rowCount = 0;this->excel.columnCount = 0;this->excel.sheetCount = this->excel.workSheets->property("Count").toInt();qDebug() << "Sheet num: " << this->excel.sheetCount << "\n";}void ExcelProcess::closeExcelFile()
{if (this->excel.current_workBook != nullptr) {this->excel.current_workBook->dynamicCall("Save()");this->excel.current_workBook->dynamicCall("Close()"); //关闭文件}if (this->excel.workBooks != nullptr) {this->excel.workBooks->dynamicCall("Close()"); //关闭文件}this->excel.excel->dynamicCall("Quit(void)");   // 退出delete this->excel.workBooks;delete this->excel.excel;this->initExcel();return ;
}void ExcelProcess::readExcel_OneSheet(int sheet_num)
{if (sheet_num > this->excel.sheetCount) {return;}// 读取一个 sheetthis->excel.current_workSheet = this->excel.current_workBook->querySubObject("Sheets(int)", sheet_num);this->excel.usedRange = this->excel.current_workSheet->querySubObject("UsedRange");if (nullptr == this->excel.usedRange || this->excel.usedRange->isNull()) {return;}QVariant var = this->excel.usedRange->dynamicCall("Value");delete this->excel.usedRange;this->excel.usedRange = nullptr;// 读取一个 sheet 结束for (int i = 0; i < this->xls_data.count(); i++) {this->xls_data.value(i).clear();}this->xls_data.clear();QVariantList varRows = var.toList();if (varRows.isEmpty()) {return;}const int rowCount = varRows.size();this->excel.rowCount = rowCount;QVariantList rowData;for (int i = 0; i < rowCount; i++){rowData = varRows[i].toList();if (rowData.count() > this->excel.columnCount) {this->excel.columnCount = rowData.count();}this->xls_data.push_back(rowData);}//this->excel.current_workBook->dynamicCall("Close()");qDebug() << "Sheet:: row:" << this->excel.rowCount << "colum:" << this->excel.columnCount << "\n";this->ui->ComBox_Sheet->clear();for (int i = 1; i <= this->excel.sheetCount; i++) {this->ui->ComBox_Sheet->addItem(QString::number(i));}this->ui->ComBox_Row->clear();for (int i = 1; i <= this->excel.rowCount; i++) {this->ui->ComBox_Row->addItem(QString::number(i));}this->ui->ComBox_Column->clear();for (int i = 1; i <= this->excel.columnCount; i++) {this->ui->ComBox_Column->addItem(QString::number(i));}}void ExcelProcess::showOneSheet(int sheet_num)
{this->readExcel_OneSheet(sheet_num);this->tab_model->clear();for (int i = 0; i < this->xls_data.count(); i++) {for (int j = 0; j < this->xls_data.at(i).count(); j++) {QStandardItem *item = new QStandardItem(QString(this->xls_data.at(i).at(j).toByteArray()));this->tab_model->setItem(i, j, item);//delete item;}}this->ui->TbleView_table1->setModel(this->tab_model);//this->ui->TbleView_table1->setSectionResizeMode(QHeaderView::Stretch);//delete model;
}void ExcelProcess::excelModeDisplay_00()
{this->ui->Lab_Row->setText("Row:");this->ui->Lab_Column->setText("Row:");this->ui->ComBox_Column->clear();for (int i = 1; i <= this->excel.columnCount; i++) {this->ui->ComBox_Column->addItem(QString::number(i));}this->ui->TbleView_table1->show();this->ui->Lab_Sheet->hide();this->ui->Lab_Row->hide();this->ui->Lab_Column->hide();this->ui->ComBox_Sheet->hide();this->ui->ComBox_Row->hide();this->ui->ComBox_Column->hide();this->ui->Btn_CalcRun->hide();this->ui->Btn_RangeRun->hide();this->ui->ComBox_Mode->setCurrentIndex(0);
}void ExcelProcess::excelModeDisplay_01()
{this->ui->Lab_Row->setText("Col_s:");this->ui->Lab_Column->setText("Col_d:");this->ui->ComBox_Mode->setCurrentIndex(1);this->ui->ComBox_Row->clear();this->ui->ComBox_Column->clear();for (int i = 1; i <= this->excel.columnCount; i++) {this->ui->ComBox_Row->addItem(QString::number(i));}for (int i = 1; i <= this->excel.columnCount + 1; i++) {this->ui->ComBox_Column->addItem(QString::number(i));}this->ui->ComBox_Column->setCurrentIndex(this->ui->ComBox_Column->count() - 1);this->ui->Lab_Sheet->show();this->ui->Lab_Row->show();this->ui->Lab_Column->show();this->ui->TbleView_table1->show();this->ui->ComBox_Sheet->show();this->ui->ComBox_Row->show();this->ui->ComBox_Column->show();this->ui->Btn_CalcRun->show();this->ui->Btn_RangeRun->hide();
}void ExcelProcess::excelModeDisplay_02()
{this->ui->Lab_Row->setText("Col_s:");this->ui->Lab_Column->setText("Col_d:");this->ui->ComBox_Mode->setCurrentIndex(2);this->ui->ComBox_Row->clear();this->ui->ComBox_Column->clear();for (int i = 1; i <= this->excel.columnCount; i++) {this->ui->ComBox_Row->addItem(QString::number(i));}for (int i = 1; i <= this->excel.columnCount + 1; i++) {this->ui->ComBox_Column->addItem(QString::number(i));}this->ui->ComBox_Column->setCurrentIndex(this->ui->ComBox_Column->count() - 1);this->ui->Lab_Sheet->show();this->ui->Lab_Row->show();this->ui->Lab_Column->show();this->ui->TbleView_table1->show();this->ui->ComBox_Sheet->show();this->ui->ComBox_Row->show();this->ui->ComBox_Column->show();this->ui->Btn_CalcRun->hide();this->ui->Btn_RangeRun->show();
}void ExcelProcess::convertToColName(int data, QString &res)
{Q_ASSERT(data>0 && data<65535);int tempData = data / 26;if(tempData > 0) {int mode = data % 26;convertToColName(mode,res);convertToColName(tempData,res);} else {res=(to26AlphabetString(data)+res);}
}QString ExcelProcess::to26AlphabetString(int data)
{QChar ch = (QChar)(data + 0x40);//A对应0x41return QString(ch);
}void ExcelProcess::castListListVariant2Variant(const QList<QList<QVariant> > &cells, QVariant &res)
{QVariantList vars;const int rows = cells.size();      //获取行数for(int i = 0; i < rows; ++i){vars.append(QVariant(cells[i]));    //将list(i)添加到QVariantList中 QVariant(cells[i])强制转换}res = QVariant(vars);   //强制转换
}void ExcelProcess::initUi()
{this->setWindowTitle(APPNAME);this->setWindowIcon(QIcon(":/bk/pic/ExcelTool.ico"));this->ui->Lab_FilePath->setText("File Path:");this->ui->PBtn_View->setText("Open File");//this->ui->Lab_BottomBar->setText("");this->ui->Lab_Background->setText("");movie_01 = new QMovie(":/bk/pic/bk_01.gif");this->ui->Lab_Background->setGeometry(0, 0, 700, 500);this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();this->ui->Lab_Sheet->hide();this->ui->Lab_Row->hide();this->ui->Lab_Column->hide();this->ui->ComBox_Sheet->hide();this->ui->ComBox_Row->hide();this->ui->ComBox_Column->hide();this->ui->Lab_Mode->hide();this->ui->ComBox_Mode->hide();this->ui->Btn_CalcRun->hide();this->ui->Btn_RangeRun->hide();for (int i = 0; i < MODECOUNT; i++) {this->ui->ComBox_Mode->addItem(excel_mode[i]);}this->ui->ComBox_Mode->setCurrentIndex(0);this->ui->TbleView_table1->hide();return ;}void ExcelProcess::initExcel()
{this->excel.excel = new QAxObject("Excel.Application");   // 加载 excel 驱动this->excel.excel->setProperty("Visible", false);//不显示Excel界面,如果为true会看到启动的Excel界面//this->excel.excel->setProperty("Visible", true);this->excel.workBooks = this->excel.excel->querySubObject("WorkBooks");
}void ExcelProcess::on_PBtn_View_clicked()
{*this->fileName = this->ui->LEdit_FilePath->text();if ((0 == this->fileName->right(3).compare("xls")) || (0 == this->fileName->right(4).compare("xlsx")) || this->fileName->isEmpty()) {;} else {this->movie_01->stop();this->movie_01->setFileName(":/bk/pic/bk_04.gif");this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();return ;}if ("Done" == this->ui->PBtn_View->text()) {//QThread::usleep(5);this->ui->LEdit_FilePath->setEnabled(true);this->ui->PBtn_View->setText("Open File");this->tab_model->clear();this->ui->Lab_Sheet->hide();this->ui->Lab_Row->hide();this->ui->Lab_Column->hide();this->ui->ComBox_Sheet->hide();this->ui->ComBox_Row->hide();this->ui->ComBox_Column->hide();this->ui->Lab_Mode->hide();this->ui->ComBox_Mode->hide();this->ui->Btn_CalcRun->hide();this->ui->Btn_RangeRun->hide();this->ui->TbleView_table1->hide();this->movie_01->stop();this->movie_01->setFileName(":/bk/pic/bk_01.gif");this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();this->closeExcelFile();} else {if (this->ui->LEdit_FilePath->text().isEmpty()) {this->showFiles();} else {//QThread::usleep(5);this->excelModeDisplay_00();this->ui->LEdit_FilePath->setEnabled(false);this->ui->PBtn_View->setText("Done");this->movie_01->stop();this->movie_01->setFileName(":/bk/pic/bk_02.gif");this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();this->openExcelFile();this->showOneSheet(1);this->ui->TbleView_table1->setStyleSheet("background-color:transparent");this->ui->TbleView_table1->horizontalHeader()->setStyleSheet("QHeaderView::section{background:transparent},QHeaderView::Stretch");this->ui->TbleView_table1->verticalHeader()->setStyleSheet("QHeaderView::section{background:transparent}");this->ui->TbleView_table1->setCornerButtonEnabled(false);this->ui->Lab_Mode->show();this->ui->ComBox_Mode->show();this->ui->TbleView_table1->show();}}}void ExcelProcess::on_ComBox_Mode_currentIndexChanged(int index)
{switch(index) {case 0: {this->excelModeDisplay_00();break;}case 1: {this->excelModeDisplay_01();break;}case 2: {this->excelModeDisplay_02();break;}default: {break;}}return ;
}void ExcelProcess::on_Btn_CalcRun_clicked()
{this->calcMode.sheet = this->ui->ComBox_Sheet->currentText().toInt();this->calcMode.col_src = this->ui->ComBox_Row->currentText().toInt();this->calcMode.col_dest = this->ui->ComBox_Column->currentText().toInt();QString data, num1, num2, result;qDebug() << "Sheet::" << this->calcMode.sheet;this->showOneSheet(this->calcMode.sheet);QList<QVariant> data_total;for (int i = 0; i < this->excel.rowCount; i++) {data = this->xls_data.at(i).at(this->calcMode.col_src - 1).toByteArray();bool flag = true;num1.clear();num2.clear();for (int i_d = 0; i_d < data.length(); i_d++) {if ('-' == data.at(i_d)) {flag = false;continue;}if (flag) {num1 += data.at(i_d);} else {num2 += data.at(i_d);}}QList<QVariant> data_row;result = QString::number(num2.toInt() - num1.toInt());qDebug() << "num1:" << num1 << "num2:" << num2 << "res:" << result << "\n";data_row.append(QString::number(num2.toInt() - num1.toInt() + 1));data_total.append(QVariant(data_row));}QString col_num, target;this->convertToColName(this->calcMode.col_dest, col_num);qDebug() << "Col:" << col_num << "\n";target = col_num + "1:" + col_num + QString::number(this->excel.rowCount);qDebug() << target ;this->excel.current_workSheet = this->excel.current_workBook->querySubObject("Sheets(int)", this->calcMode.sheet);this->excel.usedRange = this->excel.current_workSheet->querySubObject("Range(const QString)", target);this->excel.usedRange->setProperty("NumberFormat", "@");    //  设置所有单元格为文本属性this->excel.usedRange->dynamicCall("SetValue(const QVariant&", QVariant(data_total));this->excel.current_workBook->dynamicCall("Save()");//this->excel.current_workBook->dynamicCall("Close()");this->showOneSheet(this->calcMode.sheet);delete this->excel.usedRange;}void ExcelProcess::on_LEdit_FilePath_textChanged(const QString &arg1)
{if (arg1.isEmpty()) {this->movie_01->stop();this->movie_01->setFileName(":/bk/pic/bk_01.gif");this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();*this->fileName = "";} else if ((0 == arg1.right(3).compare("xls")) || (0 == arg1.right(4).compare("xlsx"))) {this->movie_01->stop();this->movie_01->setFileName(":/bk/pic/bk_03.gif");this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();*this->fileName = this->ui->LEdit_FilePath->text();} else {this->movie_01->stop();this->movie_01->setFileName(":/bk/pic/bk_04.gif");this->ui->Lab_Background->setMovie(movie_01);movie_01->setScaledSize(this->ui->Lab_Background->size());movie_01->start();}return ;
}void ExcelProcess::on_Btn_RangeRun_clicked()
{this->calcMode.sheet = this->ui->ComBox_Sheet->currentText().toInt();this->calcMode.col_src = this->ui->ComBox_Row->currentText().toInt();this->calcMode.col_dest = this->ui->ComBox_Column->currentText().toInt();QString data;int num_src = 0, num1 = 0, num2 = 0;qDebug() << "Sheet::" << this->calcMode.sheet;this->showOneSheet(this->calcMode.sheet);QList<QVariant> data_total;for (int i = 0; i < this->excel.rowCount; i++) {data = this->xls_data.at(i).at(this->calcMode.col_src - 1).toByteArray();num_src = data.toInt();num1 = num2 + 1;num2 = num_src + num1 - 1;QList<QVariant> data_row;qDebug() << "src:" << num_src << "num1:" << num1 << "num2:" << num2 << "\n";qDebug() << "range:" << (QString::number(num1) + "-" + QString::number(num2)) << "\n";data_row.append(QString::number(num1) + "-" + QString::number(num2));data_total.append(QVariant(data_row));}QString col_num, target;this->convertToColName(this->calcMode.col_dest, col_num);qDebug() << "Col:" << col_num << "\n";target = col_num + "1:" + col_num + QString::number(this->excel.rowCount);qDebug() << target ;this->excel.current_workSheet = this->excel.current_workBook->querySubObject("Sheets(int)", this->calcMode.sheet);this->excel.usedRange = this->excel.current_workSheet->querySubObject("Range(const QString)", target);this->excel.usedRange->setProperty("NumberFormat", "@");    //  设置所有单元格为文本属性this->excel.usedRange->dynamicCall("SetValue(const QVariant&", QVariant(data_total));this->excel.current_workBook->dynamicCall("Save()");//this->excel.current_workBook->dynamicCall("Close()");this->showOneSheet(this->calcMode.sheet);delete this->excel.usedRange;}

5.4. main.cpp

#include "excelprocess.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);ExcelProcess w;w.show();return a.exec();
}

5.5. excelprocess.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>ExcelProcess</class><widget class="QMainWindow" name="ExcelProcess"><property name="geometry"><rect><x>0</x><y>0</y><width>700</width><height>500</height></rect></property><property name="windowTitle"><string>ExcelProcess</string></property><widget class="QWidget" name="centralwidget"><widget class="QLineEdit" name="LEdit_FilePath"><property name="geometry"><rect><x>80</x><y>420</y><width>490</width><height>24</height></rect></property></widget><widget class="QPushButton" name="PBtn_View"><property name="geometry"><rect><x>590</x><y>417</y><width>80</width><height>30</height></rect></property><property name="text"><string>Open File</string></property></widget><widget class="QLabel" name="Lab_FilePath"><property name="geometry"><rect><x>10</x><y>420</y><width>60</width><height>24</height></rect></property><property name="text"><string>File Path:</string></property></widget><widget class="QLabel" name="Lab_Background"><property name="geometry"><rect><x>700</x><y>500</y><width>53</width><height>16</height></rect></property><property name="text"><string>TextLabel</string></property></widget><widget class="QTableView" name="TbleView_table1"><property name="geometry"><rect><x>19</x><y>280</y><width>531</width><height>100</height></rect></property></widget><widget class="QComboBox" name="ComBox_Sheet"><property name="geometry"><rect><x>80</x><y>390</y><width>60</width><height>24</height></rect></property></widget><widget class="QLabel" name="Lab_Sheet"><property name="geometry"><rect><x>30</x><y>390</y><width>50</width><height>24</height></rect></property><property name="text"><string>Sheet:</string></property></widget><widget class="QLabel" name="Lab_Row"><property name="geometry"><rect><x>170</x><y>390</y><width>50</width><height>24</height></rect></property><property name="text"><string>Row_s:</string></property></widget><widget class="QComboBox" name="ComBox_Row"><property name="geometry"><rect><x>220</x><y>390</y><width>50</width><height>24</height></rect></property></widget><widget class="QLabel" name="Lab_Column"><property name="geometry"><rect><x>280</x><y>390</y><width>50</width><height>24</height></rect></property><property name="text"><string>Col_d:</string></property></widget><widget class="QComboBox" name="ComBox_Column"><property name="geometry"><rect><x>330</x><y>390</y><width>50</width><height>24</height></rect></property></widget><widget class="QComboBox" name="ComBox_Mode"><property name="geometry"><rect><x>620</x><y>280</y><width>70</width><height>24</height></rect></property></widget><widget class="QLabel" name="Lab_Mode"><property name="geometry"><rect><x>565</x><y>280</y><width>50</width><height>24</height></rect></property><property name="text"><string>Mode:</string></property></widget><widget class="QPushButton" name="Btn_CalcRun"><property name="geometry"><rect><x>620</x><y>350</y><width>70</width><height>30</height></rect></property><property name="text"><string>Run</string></property></widget><widget class="QPushButton" name="Btn_RangeRun"><property name="geometry"><rect><x>620</x><y>350</y><width>70</width><height>30</height></rect></property><property name="text"><string>Run</string></property></widget><zorder>Lab_Background</zorder><zorder>Lab_FilePath</zorder><zorder>PBtn_View</zorder><zorder>LEdit_FilePath</zorder><zorder>TbleView_table1</zorder><zorder>ComBox_Sheet</zorder><zorder>Lab_Sheet</zorder><zorder>Lab_Row</zorder><zorder>ComBox_Row</zorder><zorder>Lab_Column</zorder><zorder>ComBox_Column</zorder><zorder>ComBox_Mode</zorder><zorder>Lab_Mode</zorder><zorder>Btn_CalcRun</zorder><zorder>Btn_RangeRun</zorder></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>700</width><height>26</height></rect></property></widget><widget class="QStatusBar" name="statusbar"/></widget><resources/><connections/>
</ui>

#完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/63186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM的故事——类文件结构

类文件结构 文章目录 类文件结构一、概述二、无关性基石三、Class类文件的结构 一、概述 计算机是只认由0、1组成的二进制码的&#xff0c;不过随着发展&#xff0c;我们编写的程序可以被编译成与指令集无关、平台中立的一种格式。 二、无关性基石 对于不同平台和不同平台的…

docker命令学习

docker vscode插件出现的问题 docker命令 docker images &#xff08;查看所有的镜像&#xff09; docker ps -a &#xff08;查看所有的容器&#xff09; docker ps &#xff08;查看运行的容器&#xff09; docker run imageID docker run --gpus all --shm-size8g -it imag…

网络安全体系架构介绍

网络安全体系是一项复杂的系统工程&#xff0c;需要把安全组织体系、安全技术体系和安全管理体系等手段进行有机融合&#xff0c;构建一体化的整体安全屏障。针对网络安全防护&#xff0c;美国曾提出多个网络安全体系模型和架构&#xff0c;其中比较经典的包括PDRR模型、P2DR模…

Revit SDK 介绍:AvoidObstruction 避免碰撞

前言 这个例子介绍如何让碰撞在一起的管道避免碰撞&#xff0c;即对管道进行调整。 内容 调整前&#xff1a; 调整后&#xff1a; 从结果来看&#xff0c;所有的碰撞都被调整了。作为一个例子&#xff0c;不会去考虑是否合理&#xff0c;仅仅是展示了一下 Revit API 的能…

我开课了!《机器学习》公益课9月4日开课

我是黄海广&#xff0c;大学老师&#xff0c;我上的一门课叫《机器学习》&#xff0c;本科生学机器学习有点难&#xff0c;但也不是没有可能&#xff0c;我在摸索中&#xff0c;设计适合本科生的机器学习课程&#xff0c;写了教材&#xff0c;录了视频&#xff0c;做了课件。我…

手写Openfeign实现原理——极简版

文章目录 前言Openfeign实现思路前期准备基本依赖项 开始实现自定义注解自定义代理类定义创建代理对象的工厂InstantiationAwareBeanPostProcessor实现bean的注入OpenInstantiationAwareBeanPostProcessor 自定义 feign接口启动类小结 踩坑记录ImportComponent和Configuration区…

HTTP与SOCKS5的区别对比

在互联网世界中&#xff0c;服务器是一种重要的工具&#xff0c;可以帮助我们提高网络安全性等。今天&#xff0c;我们将重点关注两种常见的技术&#xff1a;HTTP和SOCKS5。让我们深入了解它们的工作原理、用途和优缺点&#xff0c;并通过Python代码示例学习如何使用它们。 HT…

一文了解tcp/ip协议的运行原理

接触代理ip的人都了解https/sock5等ip协议&#xff0c;那么TCP/IP 协议又是什么&#xff1f; 一、什么是TCP/IP 协议&#xff1f; TCP/IP 协议实际上是一系列网络通信协议的一个统称&#xff0c;他负责具体的数据传输工作&#xff0c;核心的两个协议包括TCP以及IP&#xff0c…

Unity3D 如何在ECS架构下,用Unity引擎进行游戏开发详解

前言 Unity3D是一款强大的游戏引擎&#xff0c;它提供了丰富的功能和工具&#xff0c;可以帮助开发者快速构建高质量的游戏。而Entity Component System&#xff08;ECS&#xff09;是Unity3D中一种新的架构模式&#xff0c;它可以提高游戏的性能和可扩展性。本文将详细介绍在…

Flink 如何定位反压节点?

分析&回答 Flink Web UI 自带的反压监控 —— 直接方式 Flink Web UI 的反压监控提供了 Subtask 级别的反压监控。监控的原理是通过Thread.getStackTrace() 采集在 TaskManager 上正在运行的所有线程&#xff0c;收集在缓冲区请求中阻塞的线程数&#xff08;意味着下游阻…

Redis数据结构总结

Redis 是一款开源的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息代理。Redis 支持多种类型的数据结构&#xff0c;如字符串&#xff08;String&#xff09;、哈希&#xff08;Hashes&#xff09;、列表&#xff08;Lists&#xff09;、集合&…

vue3的面试题

ref里面放对象发生的事情 ref只会对对象的属性进行响应式转换&#xff0c;而不会对对象的原型链上的属性进行转换。如果需要对对象的原型链上的属性进行响应式转换&#xff0c;可以使用reactive函数。 toRefs的适用场景&#xff1f; toRefs是Vue 3中的一个响应式API&#xf…

使用环境中的视觉地标和扩展卡尔曼滤波器定位移动机器人研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

SQL高阶语句

目录 1、概念 1.1、概述 1.2、常见的MySQL高阶语句的概念&#xff1a; 1.3、 SQL高阶语句的作用 2、常用查询 2.1、按关键字排序 2.1.1、概述和作用 2.1.2、 &#xff08;1&#xff09;语法 2.1.3、模板表&#xff1a;ky30 ​编辑2.1.4、分数按降序排列 2.1.5、ORDER…

Kafka环境搭建与相关启动命令

一、Kafka环境搭建 点击下载kafka_2.11-2.3.1.tgz文件链接 1、上传kafka_2.11-2.3.1.tgz&#xff0c;解压kafka_2.11-2.3.1.tgz&#xff0c;得到kafka_2.11-2.3.1文件夹 1&#xff09;上传 #使用mobaxterm将 kafka_2.11-2.3.1.tgz 传入tools文件夹 #用下面代码进入tools文件…

SPSS统计作图教程:频率多边形

SPSS统计作图教程&#xff1a;频率多边形 1、问题与数据 某研究者想了解某数据集中最大携氧能力&#xff08;VO2max&#xff09;是否服从正态分布&#xff0c;部分数据如图1。研究者应如何绘图查看呢&#xff1f; 图1 部分数据 2、对问题的分析 研究者想绘图展示最大携氧能…

深入理解 JVM 之——Java 内存区域与溢出异常

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 本篇为深入理解 Java 虚拟机第二章内容&#xff0c;推荐在学习前先掌握基础的 Linux 操作、编译原理、计算机组成原理等计算机基础以及扎实的 C/C 功底。 该系列的 GitHub 仓库&#xff1a;https://github…

go学习part20(1)反射

283_尚硅谷_反射基本介绍和示意图_哔哩哔哩_bilibili 1.介绍 1&#xff09;基本数据类型的类型和类别一致&#xff0c;但是结构体等不一样。 2)反射的例子&#xff08;桥连接&#xff0c;序列化&#xff09; 序列化指定tag&#xff0c;会反射生成tag字符串 3&#xff09;refl…

Vue在表格中拿到该行信息的方式(作用域插槽-#default-scope-解决按钮与行点击的顺序问题)

遇到的问题 在做表格的时候&#xff0c;表格是封装好了的&#xff0c;用于展示数据。如果想给单行增加按钮&#xff0c;可以单独写一列存放按钮&#xff0c;最基本的需求是&#xff0c;点击按钮后要拿到数据然后发起请求。 且Vue的element-plus&#xff0c;当我们点击按钮之后…

Linux挖矿程序清除

1. 找到挖矿进程 2.找到病毒的文件地址 ls -l /proc/进程ID/exe3.删除文件命令 rm -rf 文件地址4.杀死挖矿进程 kill -9 进程ID