一、效果演示
(1)查询SQlite数据库页面
其中数据库表中是用软件手动添加的,推荐一个软件,需要的话找我要安装包,也可以网页搜索 SQLite Expert Prefessional
(2)点击导出操作日志,选择保存文件位置和文件名
(3)保存后进入子线程中执行导出操作,不影响UI界面操作
二、详细代码
(1)获取tablewidget中表格数据。开始选择用QMap接收,所以就只获取表格后两列信息,用信号发到子线程中导出,报错显示信号与槽参数不能是QMap类型,又转成QVariantMap类型。
QMap<QString, QString> keyValueMap;
// 遍历表格并存储第二列和第三列信息到QMap容器
for (int row = 0; row < ui->tableWidget->rowCount(); ++row) {
QTableWidgetItem *keyItem = ui->tableWidget->item(row, 1); // 第二列
QTableWidgetItem *valueItem = ui->tableWidget->item(row, 2); // 第三列
if (keyItem && valueItem) {
QString key = keyItem->text();
QString value = valueItem->text();
keyValueMap.insert(key, value);
}
}
QVariantMap variantMap;
for (auto it = keyValueMap.begin(); it != keyValueMap.end(); ++it) {
variantMap.insert(it.key(), it.value());
}
(2)开启子线程执行导出操作
(1)和(2)都是在保存操作日志按钮槽函数中,首先弹出选择保存位置和文件名的选择框,SaveThread是继承自QObject的一类,专用于执行子线程导出操作。使用movetoThread()方法添加到子线程中,发送保存的文件名(子线程用会用到)和tablewidget中表格的数据。
QString fileName = QFileDialog::getSaveFileName(this,tr("Excle file"),QString("./test.xlsx"),tr("Excel Files(*.xlsx)")); //设置保存的文件名
if(fileName != NULL)
{
SaveThread *work = new SaveThread();
thread = new QThread;
work->moveToThread(thread);
connect(this,&OperatorRecord::thread_save,work,&SaveThread::SaveOperatorThread);
connect(this,&OperatorRecord::thread_filename,work,&SaveThread::filenamethread);
connect(work,&SaveThread::threadend,this,&OperatorRecord::savesuccess);
thread_filename(fileName);
thread_save(variantMap);
thread->start();
}
(3)子线程中导出操作,之前用QMap写好了,后改的QVariantMap,所以接收到又转为QMap类型。因为之前发来的表格数据只有后两列(时间和操作),创建excl表格时加了一列序号。完成之后发送子线程结束信号,销毁子线程释放内存。
void SaveThread::SaveOperatorThread(QVariantMap variantMap)
{
QMap<QString, QString> keyValueMap;
for (auto it = variantMap.begin(); it != variantMap.end(); ++it) {
keyValueMap.insert(it.key(), it.value().toString());
}
QMap<QString, QString>::const_iterator iter = keyValueMap.constBegin();
QAxObject* excel = new QAxObject("Excel.Application", this);
excel->dynamicCall("SetVisible(bool)", false);
excel->setProperty("DisplayAlerts", false);
QAxObject* workbooks = excel->querySubObject("Workbooks");
workbooks->dynamicCall("Add");
QAxObject* workbook = excel->querySubObject("ActiveWorkbook");
QAxObject* worksheet = workbook->querySubObject("Worksheets(int)", 1);
int rowCount = keyValueMap.size();
int columnCount = 3;
// 写入标题
for (int i = 1; i <= columnCount; i++) {
QAxObject* cell = worksheet->querySubObject("Cells(int,int)", 1, i);
cell->setProperty("RowHeight", 40);
if (i == 1)
cell->dynamicCall("SetValue(const QString&)", "序号");
else if (i == 2)
cell->dynamicCall("SetValue(const QString&)", "操作时间");
else if (i == 3)
cell->dynamicCall("SetValue(const QString&)", "操作");
}
// 写入数据
int row = 2;
for (auto it = keyValueMap.begin(); it != keyValueMap.end(); ++it) {
QAxObject* cell = worksheet->querySubObject("Cells(int,int)", row, 1);
cell->dynamicCall("SetValue(int)", row - 2);
cell = worksheet->querySubObject("Cells(int,int)", row, 2);
cell->dynamicCall("SetValue(const QString&)", it.key());
cell = worksheet->querySubObject("Cells(int,int)", row, 3);
cell->dynamicCall("SetValue(const QString&)", it.value());
++row;
}
// 保存文件
workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(save_filename));
workbook->dynamicCall("Close()");
excel->dynamicCall("Quit()");
delete excel;
excel = nullptr;
threadend();//线程结束信号
}
void SaveThread::filenamethread(QString filename)
{
save_filename = filename;
}