【Qt | QTableWidget】Qt 中导出 QTableWidget 数据到 Excel 的 4 种实用方法

十八、QT之导出数据到EXCEL ExcelAPI.h #ifndef EXCEL_H #define EXCEL_H #include <QObject> #include <QMutex> #include <QStringList> class ExcelAPI : public QObject { Q_OBJECT private: explicit ExcelAPI... 阅读详情

😁博客主页😁:🚀https://blog.youkuaiyun.com/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍导出 QTableWidget 数据到 Excel 的 4 种方法 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:

本文未经允许,不得转发!!!


在这里插入图片描述
在这里插入图片描述

🎄一、概述

在 Qt 应用程序开发中,数据导出是常见的需求。QTableWidget 作为 Qt 中常用的数据展示组件,经常需要将其内容导出为 Excel 格式以便于分享或进一步分析。

本文将系统性地介绍 四种实现方法,涵盖从最简单的纯文本方案到功能完整的第三方库方案。每种方法均被封装为独立的导出函数,只需将 QTableWidget 指针 作为参数传入即可使用。


在这里插入图片描述

🎄二、方法一:CSV 格式导出(最简方案)

逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。

这是最快速、兼容性最好的方案。CSV 文件可以被几乎所有电子表格软件(Excel、WPS、LibreOffice)识别。

核心思路:将表格数据格式化为逗号分隔的文本文件,并正确处理特殊字符。

实现代码与步骤
此函数完成了:文件保存对话框、数据格式化、中文编码处理和完整的用户反馈。

/**
 * @brief 将 QTableWidget 数据导出为 CSV 文件
 * @param tableWidget 需要导出的表格控件指针
 * @return true 导出成功,false 导出失败
 */
bool saveTableWidgetToCSV(QTableWidget *tableWidget)
{
    // 1. 参数有效性检查
    if (!tableWidget) {
        QMessageBox::warning(nullptr, "导出失败", "表格对象为空");
        return false;
    }
    if (tableWidget->rowCount() == 0 && tableWidget->columnCount() == 0) {
        QMessageBox::warning(nullptr, "导出失败", "表格数据为空");
        return false;
    }
    
    // 2. 获取保存路径
    QString fileName = QFileDialog::getSaveFileName(nullptr, 
        "保存为CSV文件", "data.csv", "CSV文件 (*.csv)");
    if (fileName.isEmpty()) return false;
    
    // 3. 确保文件扩展名
    if (!fileName.endsWith(".csv", Qt::CaseInsensitive)) {
        fileName += ".csv";
    }
    
    // 4. 创建文件并写入数据
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::critical(nullptr, "导出失败", 
            QString("无法创建文件:\n%1").arg(fileName));
        return false;
    }
    
    QTextStream out(&file);
    out.setCodec("UTF-8");  // 关键:设置UTF-8编码支持中文
    
    // 5. 写入表头
    for (int col = 0; col < tableWidget->columnCount(); ++col) {
        QTableWidgetItem *header = tableWidget->horizontalHeaderItem(col);
        if (header) {
            // 处理包含逗号或引号的单元格内容
            QString text = header->text().replace("\"", "\"\"");
            out << "\"" << text << "\"";
        } else {
            out << QString("列%1").arg(col + 1);
        }
        if (col < tableWidget->columnCount() - 1) out << ",";
    }
    out << "\n";
    
    // 6. 写入数据行
    int exportedRows = 0;
    for (int row = 0; row < tableWidget->rowCount(); ++row) {
        bool rowHasData = false;

        for (int col = 0; col < tableWidget->columnCount(); ++col) {
            QTableWidgetItem *item = tableWidget->item(row, col);

            if (item && !item->text().isEmpty()) {
                rowHasData = true;
            }

            if (item) {
                QString text = item->text().replace("\"", "\"\"");
                out << "\"" << text << "\"";
            }
            if (col < tableWidget->columnCount() - 1) out << ",";
        }
        out << "\n";

        if (rowHasData) exportedRows++;
    }
    
    file.close();
    
    // 7. 导出结果反馈
    if (exportedRows == 0 && tableWidget->columnCount() > 0) {
        QMessageBox::information(nullptr, "导出完成",
            "文件已保存,但所有行数据为空");
        return true;
    }
    //QMessageBox::information(nullptr, "导出成功",
    //    QString("数据已成功导出到:\n%1\n\n总计导出: %2 行 × %3 列")
    //    .arg(fileName).arg(exportedRows).arg(tableWidget->columnCount()));

	QString message = QString("数据已成功导出到:\n%1\n\n"
                     "总计导出: %2 行 × %3 列\n\n"
                     "说明:此文件csv格式,可被Excel/WPS等表格软件打开")
                     .arg(fileName).arg(exportedRows).arg(tableWidget->columnCount());
    QMessageBox msgBox(QMessageBox::Information, "导出成功", message);
    msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Open);
    msgBox.setButtonText(QMessageBox::Open, "打开文件");

    if (msgBox.exec() == QMessageBox::Open) {
        QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
    }
    
    return true;
}

运行结果:
在这里插入图片描述

优点:

  • 无需任何第三方库

  • 跨平台兼容性好

  • 实现简单,代码量少

缺点:

  • 导出的是纯文本格式,非原生 Excel 文件

  • 不支持单元格格式、公式等高级特性


在这里插入图片描述

🎄三、方法二:制表符分隔方案(改良版)

这是对 CSV 方案的优化,使用制表符 (\t) 作为分隔符,并以 .xls 或 .xlsx 扩展名保存,Excel 会自动识别为表格数据。

实现代码

/**
 * @brief 使用制表符分隔将 QTableWidget 数据导出为 Excel 可识别的文件
 * @param tableWidget 需要导出的表格控件指针
 * @return true 导出成功,false 导出失败
 */
bool saveTableWidgetToExcelWithTab(QTableWidget *tableWidget)
{
    // 1. 参数有效性检查
    if (!tableWidget) {
        QMessageBox::warning(nullptr, "导出失败", "表格对象为空");
        return false;
    }
    if (tableWidget->rowCount() == 0 && tableWidget->columnCount() == 0) {
        QMessageBox::warning(nullptr, "导出失败", "表格数据为空");
        return false;
    }

    // 2. 获取保存路径
    QString fileName = QFileDialog::getSaveFileName(nullptr,
        "保存为Excel文件", "data.xls",
        "Excel文件 (*.xls *.xlsx);;文本文件 (*.txt);;所有文件 (*.*)");

    if (fileName.isEmpty()) return false;

    // 3. 确保文件扩展名
    if (!fileName.endsWith(".xls", Qt::CaseInsensitive) &&
        !fileName.endsWith(".xlsx", Qt::CaseInsensitive) &&
        !fileName.endsWith(".txt", Qt::CaseInsensitive)) {
        fileName += ".xls";
    }

    // 4. 创建文件并写入数据
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::critical(nullptr, "导出失败",
            QString("无法创建文件:\n%1").arg(fileName));
        return false;
    }

    QTextStream out(&file);
    out.setCodec("UTF-8");  // 关键:设置UTF-8编码支持中文
//    out.setGenerateByteOrderMark(true);

    try {
        int exportedRows = 0;

        // 5. 写入表头
        for (int col = 0; col < tableWidget->columnCount(); ++col) {
            QTableWidgetItem *header = tableWidget->horizontalHeaderItem(col);
            if (header) {
                QString text = header->text();
                text.replace("\t", " ");
                text.replace("\n", " ");
                text.replace("\r", "");
                out << text;
            } else {
                out << QString("列%1").arg(col + 1);
            }

            if (col < tableWidget->columnCount() - 1) {
                out << "\t";
            }
        }
        out << "\n";

        // 6. 写入数据行
        for (int row = 0; row < tableWidget->rowCount(); ++row) {
            bool rowHasData = false;

            for (int col = 0; col < tableWidget->columnCount(); ++col) {
                QTableWidgetItem *item = tableWidget->item(row, col);

                if (item) {
                    QString text = item->text();

                    // 处理特殊字符
                    text.replace("\t", " ");
                    text.replace("\n", " ");
                    text.replace("\r", "");

                    // 检查是否是数字
                    bool isNumber = false;
                    bool ok;
                    text.toDouble(&ok);
                    if (ok && !text.isEmpty() &&
                        (text[0].isDigit() || text[0] == '-' || text[0] == '+')) {
                        isNumber = true;
                    }

                    // 如果以等号开头,添加单引号(防止Excel识别为公式)
                    if (!isNumber && (text.startsWith("=") || text.startsWith("+") ||
                        text.startsWith("-") || text.startsWith("@"))) {
                        text = "'" + text;
                    }

                    out << text;

                    if (!text.isEmpty()) {
                        rowHasData = true;
                    }
                }

                if (col < tableWidget->columnCount() - 1) {
                    out << "\t";
                }
            }
            out << "\n";

            if (rowHasData) exportedRows++;
        }

        file.close();

        // 7. 导出结果反馈
        QString fileType = QFileInfo(fileName).suffix().toUpper();
        QString message;

        if (exportedRows == 0) {
            message = QString("文件已保存为 %1 格式:\n%2\n\n但所有行数据为空")
                     .arg(fileType).arg(fileName);
            QMessageBox::information(nullptr, "导出完成", message);
        } else {
            message = QString("数据已成功导出为 %1 格式:\n%2\n\n"
                             "总计导出: %3 行 × %4 列\n\n"
                             "说明:此文件使用制表符分隔,可被Excel/WPS等表格软件打开")
                     .arg(fileType).arg(fileName)
                     .arg(exportedRows).arg(tableWidget->columnCount());

            QMessageBox msgBox(QMessageBox::Information, "导出成功", message);
            msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Open);
            msgBox.setButtonText(QMessageBox::Open, "打开文件");

            if (msgBox.exec() == QMessageBox::Open) {
                QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
            }
        }

        return true;

    } catch (...) {
        file.close();
        QFile::remove(fileName);
        QMessageBox::critical(nullptr, "导出失败", "导出过程中发生错误");
        return false;
    }
}

运行结果
在这里插入图片描述

优点:

  • Excel 打开时自动识别为表格,视觉体验更好

  • 比 CSV 更少遇到文本内容含分隔符导致错位的问题


在这里插入图片描述

🎄四、方法三:使用 QAxObject(Windows 专属方案)

此方法通过 Qt 的 ActiveX 支持直接操作 Excel 应用程序,可以生成功能完整的原生 Excel 文件。

实现前提:仅限 Windows 平台,且系统中需安装 Microsoft Excel。

.pro 文件配置:

QT += axcontainer  # 添加 ActiveX 支持

实现代码:

// 辅助函数:检测Excel是否安装
bool isExcelInstalled()
{
    // 方法1:检查注册表
    QSettings registry("HKEY_CLASSES_ROOT", QSettings::NativeFormat);

    // 检查不同版本的Excel
    QStringList excelProgIDs = {
        "Excel.Application",      // 默认
        "Excel.Application.16",   // Office 2016/365
        "Excel.Application.15",   // Office 2013
        "Excel.Application.14",   // Office 2010
        "Excel.Application.12"    // Office 2007
    };

    foreach (const QString &progID, excelProgIDs) {
        if (registry.contains(progID + "/CLSID")) {
            qDebug() << "检测到Excel安装:" << progID;
            return true;
        }
    }

    // 方法2:检查系统路径中的excel.exe
    QStringList systemPaths = QString(getenv("PATH")).split(";");
    foreach (const QString &path, systemPaths) {
        if (QFile::exists(path + "/excel.exe") ||
            QFile::exists(path + "/EXCEL.EXE")) {
            qDebug() << "在系统路径中找到excel.exe";
            return true;
        }
    }

    // 方法3:检查常见的Excel安装路径
    QStringList commonPaths;

    // Office 365/2019/2016
    commonPaths << "C:/Program Files/Microsoft Office/root/Office16/EXCEL.EXE";
    commonPaths << "C:/Program Files (x86)/Microsoft Office/root/Office16/EXCEL.EXE";

    // Office 2013
    commonPaths << "C:/Program Files/Microsoft Office/Office15/EXCEL.EXE";
    commonPaths << "C:/Program Files (x86)/Microsoft Office/Office15/EXCEL.EXE";

    // Office 2010
    commonPaths << "C:/Program Files/Microsoft Office/Office14/EXCEL.EXE";
    commonPaths << "C:/Program Files (x86)/Microsoft Office/Office14/EXCEL.EXE";

    // Office 2007
    commonPaths << "C:/Program Files/Microsoft Office/Office12/EXCEL.EXE";
    commonPaths << "C:/Program Files (x86)/Microsoft Office/Office12/EXCEL.EXE";

    foreach (const QString &path, commonPaths) {
        if (QFile::exists(path)) {
            qDebug() << "在常见路径中找到Excel:" << path;
            return true;
        }
    }

    qDebug() << "未检测到Excel安装";
    return false;
}

// 辅助函数:获取已安装的Excel版本
QString getInstalledExcelVersion()
{
    QSettings registry("HKEY_CLASSES_ROOT", QSettings::NativeFormat);

    QStringList versions = {
        "Excel.Application.16",   // Office 2016/365
        "Excel.Application.15",   // Office 2013
        "Excel.Application.14",   // Office 2010
        "Excel.Application.12",   // Office 2007
        "Excel.Application"       // 默认
    };

    foreach (const QString &version, versions) {
        if (registry.contains(version + "/CLSID")) {
            if (version == "Excel.Application.16") return "Office 2016/365";
            if (version == "Excel.Application.15") return "Office 2013";
            if (version == "Excel.Application.14") return "Office 2010";
            if (version == "Excel.Application.12") return "Office 2007";
            return "Office (未知版本)";
        }
    }

    return "未安装";
}

bool saveTableWidgetToExcelWithQAxObject(QTableWidget *tableWidget)
{
    if (!tableWidget) {
        QMessageBox::warning(nullptr, "导出失败", "表格对象为空");
        return false;
    }

    // 1. 首先检查Excel是否安装
    if (!isExcelInstalled()) {
        QString errorMsg = "未检测到 Microsoft Excel 安装。\n\n";
        errorMsg += "请安装以下任一版本的 Microsoft Excel:\n";
        errorMsg += "• Office 2007 或更高版本\n";
        errorMsg += "• Office 365\n\n";
        errorMsg += "或者使用其他导出格式(如CSV或制表符分隔格式)。";

        QMessageBox::critical(nullptr, "Excel未安装", errorMsg);
        return false;
    }

    // 2. 获取已安装的Excel版本信息(用于调试)
    QString excelVersion = getInstalledExcelVersion();
    qDebug() << "检测到Excel版本:" << excelVersion;

    // 3. 获取保存文件名
    QString fileName = QFileDialog::getSaveFileName(nullptr,
        "保存为Excel文件 (使用" + excelVersion + ")",
        "data.xlsx",
        "Excel文件 (*.xlsx *.xls)");

    if (fileName.isEmpty()) {
        return false;  // 用户取消
    }

    if (!fileName.endsWith(".xlsx", Qt::CaseInsensitive) &&
        !fileName.endsWith(".xls", Qt::CaseInsensitive)) {
        fileName += ".xlsx";
    }

    // 4. 显示导出进度对话框
    QProgressDialog progressDialog("正在导出Excel文件...", "取消导出", 0, 100, nullptr);
    progressDialog.setWindowModality(Qt::WindowModal);
    progressDialog.setMinimumDuration(0);
    progressDialog.setValue(10);
    QCoreApplication::processEvents();

    // 5. 尝试创建Excel对象(使用异常安全的方式)
    QAxObject *excel = nullptr;
    QAxObject *workbooks = nullptr;
    QAxObject *workbook = nullptr;
    QAxObject *worksheet = nullptr;

    try {
        progressDialog.setLabelText("正在启动Excel...");
        progressDialog.setValue(20);
        QCoreApplication::processEvents();

        // 创建Excel应用程序对象
        excel = new QAxObject();
        if (!excel) {
            throw std::runtime_error("无法创建Excel对象");
        }

        // 尝试不同版本的Excel ProgID
        QStringList excelProgIDs = {
            "Excel.Application",      // 默认
            "Excel.Application.16",   // Office 2016/365
            "Excel.Application.15",   // Office 2013
            "Excel.Application.14",   // Office 2010
            "Excel.Application.12"    // Office 2007
        };

        bool excelStarted = false;
        QString usedProgID;

        foreach (const QString &progID, excelProgIDs) {
            if (excel->setControl(progID)) {
                excelStarted = true;
                usedProgID = progID;
                qDebug() << "成功启动Excel:" << progID;
                break;
            }
        }

        if (!excelStarted) {
            throw std::runtime_error("无法启动Excel应用程序。\n"
                                   "可能的原因:\n"
                                   "1. Excel未正确安装\n"
                                   "2. Excel COM组件损坏\n"
                                   "3. 权限不足");
        }

        progressDialog.setLabelText("正在设置Excel参数...");
        progressDialog.setValue(30);
        QCoreApplication::processEvents();

        // 设置Excel属性
        excel->setProperty("Visible", false);
        excel->setProperty("DisplayAlerts", false);

        // 创建工作簿
        workbooks = excel->querySubObject("Workbooks");
        if (!workbooks || workbooks->isNull()) {
            throw std::runtime_error("无法访问Excel工作簿");
        }

        progressDialog.setLabelText("正在创建工作簿...");
        progressDialog.setValue(40);
        QCoreApplication::processEvents();

        workbook = workbooks->querySubObject("Add");
        if (!workbook || workbook->isNull()) {
            throw std::runtime_error("无法创建新工作簿");
        }

        // 获取第一个工作表
        worksheet = workbook->querySubObject("Worksheets(int)", 1);
        if (!worksheet || worksheet->isNull()) {
            throw std::runtime_error("无法访问工作表");
        }

        progressDialog.setLabelText("正在写入表头...");
        progressDialog.setValue(50);
        QCoreApplication::processEvents();

        // 写入表头
        int totalRows = tableWidget->rowCount();
        int totalCols = tableWidget->columnCount();
        int totalCells = totalRows * totalCols;
        int processedCells = 0;

        for (int col = 0; col < totalCols; ++col) {
            QTableWidgetItem *header = tableWidget->horizontalHeaderItem(col);
            QString headerText = header ? header->text() : QString("列%1").arg(col + 1);

            // 使用Range对象写入
            QString cellAddress = QString("%1%2").arg(QChar('A' + col)).arg(1);
            QAxObject *range = worksheet->querySubObject("Range(const QString&)", cellAddress);
            if (range) {
                range->setProperty("Value", headerText);

                // 尝试设置表头样式(可选)
                QAxObject *font = range->querySubObject("Font");
                if (font) {
                    font->setProperty("Bold", true);
                    delete font;
                }

                delete range;
            }
        }

        progressDialog.setLabelText("正在写入数据...");
        progressDialog.setValue(60);
        QCoreApplication::processEvents();

        // 写入数据
        for (int row = 0; row < totalRows; ++row) {
            for (int col = 0; col < totalCols; ++col) {
                QTableWidgetItem *item = tableWidget->item(row, col);
                if (item && !item->text().isEmpty()) {
                    QString cellAddress = QString("%1%2").arg(QChar('A' + col)).arg(row + 2);
                    QAxObject *range = worksheet->querySubObject("Range(const QString&)", cellAddress);
                    if (range) {
                        // 直接写入文本,避免类型转换问题
                        range->setProperty("Value", item->text());
                        delete range;
                    }
                }

                processedCells++;

                // 更新进度
                if (processedCells % 100 == 0) {
                    int progress = 60 + (processedCells * 30 / totalCells);
                    progressDialog.setValue(progress);
                    progressDialog.setLabelText(QString("正在写入数据... (%1/%2)")
                                               .arg(processedCells).arg(totalCells));
                    QCoreApplication::processEvents();

                    // 检查是否取消
                    if (progressDialog.wasCanceled()) {
                        throw std::runtime_error("用户取消了导出操作");
                    }
                }
            }
        }

        progressDialog.setLabelText("正在调整列宽...");
        progressDialog.setValue(90);
        QCoreApplication::processEvents();

        // 尝试自动调整列宽(如果失败也不影响主要功能)
        QAxObject *usedRange = worksheet->querySubObject("UsedRange");
        if (usedRange) {
            QAxObject *columns = usedRange->querySubObject("Columns");
            if (columns) {
                columns->dynamicCall("AutoFit()");
                delete columns;
            }
            delete usedRange;
        }

        progressDialog.setLabelText("正在保存文件...");
        progressDialog.setValue(95);
        QCoreApplication::processEvents();

        // 保存文件
        QVariant saveResult = workbook->dynamicCall("SaveAs(const QString&)",
            QDir::toNativeSeparators(fileName));

        if (!saveResult.toBool()) {
            qDebug() << "保存返回值:" << saveResult;
            // 即使返回false,文件可能已经保存,所以不抛出异常
        }

        progressDialog.setValue(100);
        QCoreApplication::processEvents();

        // 关闭Excel
        workbook->dynamicCall("Close()");
        excel->dynamicCall("Quit()");

        // 清理资源
        if (worksheet) {
            delete worksheet;
            worksheet = nullptr;
        }
        if (workbook) {
            delete workbook;
            workbook = nullptr;
        }
        if (workbooks) {
            delete workbooks;
            workbooks = nullptr;
        }
        if (excel) {
            delete excel;
            excel = nullptr;
        }

        // 验证文件是否成功创建
        if (QFile::exists(fileName)) {
            QMessageBox::information(nullptr, "导出成功",
                QString("Excel文件已成功保存!\n\n"
                       "文件位置: %1\n"
                       "文件大小: %2 KB\n"
                       "数据量: %3 行 × %4 列\n"
                       "使用的Excel版本: %5")
                .arg(fileName)
                .arg(QFileInfo(fileName).size() / 1024)
                .arg(totalRows)
                .arg(totalCols)
                .arg(excelVersion));

            // 询问是否打开文件
            QMessageBox msgBox;
            msgBox.setWindowTitle("导出完成");
            msgBox.setText("导出已完成,是否要打开生成的Excel文件?");
            msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
            msgBox.setDefaultButton(QMessageBox::Yes);

            if (msgBox.exec() == QMessageBox::Yes) {
                QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
            }

            return true;
        } else {
            QMessageBox::warning(nullptr, "警告",
                "文件保存命令已执行,但目标文件未创建。\n"
                "可能是权限不足或路径无效。");
            return false;
        }

    } catch (const std::exception &e) {
        // 异常处理
        QString errorDetails = QString::fromLocal8Bit(e.what());

        // 清理资源
        if (worksheet) delete worksheet;
        if (workbook) delete workbook;
        if (workbooks) delete workbooks;
        if (excel) {
            try {
                excel->dynamicCall("Quit()");
            } catch (...) {
                // 忽略退出时的异常
            }
            delete excel;
        }

        // 显示错误信息
        QString errorMsg = "导出过程中发生错误:\n\n";
        errorMsg += errorDetails + "\n\n";
        errorMsg += "建议:\n";
        errorMsg += "1. 确保Excel已正确安装并能正常启动\n";
        errorMsg += "2. 尝试使用其他导出格式(CSV或制表符分隔)\n";
        errorMsg += "3. 检查是否有足够的磁盘空间和文件权限";

        QMessageBox::critical(nullptr, "导出失败", errorMsg);
        return false;

    } catch (...) {
        // 未知异常处理
        if (excel) {
            try {
                excel->dynamicCall("Quit()");
            } catch (...) {}
            delete excel;
        }

        QMessageBox::critical(nullptr, "导出失败",
            "发生未知错误,无法导出Excel文件。\n"
            "建议使用CSV或制表符分隔格式导出。");
        return false;
    }
}

我的电脑没execl软件,无法演示。。。

优点:

  • 生成原生 Excel 文件,支持所有 Excel 特性

  • 可控制格式、公式、图表等高级功能

缺点:

  • 仅限 Windows 平台

  • 依赖 Excel 安装

  • 执行效率相对较低


在这里插入图片描述

🎄五、方法四:使用 QtXlsx(跨平台推荐方案)

QtXlsx 是一个用于读写 Excel 文件的第三方 Qt 库,无需安装 Excel,完全跨平台。而且可以带格式的导出。就是操作起来会比前面三种方式繁琐一点。关于具体操作,后面我可能会单独写一篇文章来介绍。

实现代码:

bool saveTableWidgetToExcelWithXlsx(QTableWidget *tableWidget)
{
    if (!tableWidget) {
        QMessageBox::warning(nullptr, "导出失败", "表格对象为空");
        return false;
    }

    QString fileName = QFileDialog::getSaveFileName(nullptr,
        "保存为Excel文件", "data.xlsx", "Excel文件 (*.xlsx)");

    if (fileName.isEmpty()) return false;

    if (!fileName.endsWith(".xlsx", Qt::CaseInsensitive)) {
        fileName += ".xlsx";
    }

    // 调试信息
    qDebug() << "开始导出Excel...";
    qDebug() << "表格是否有交替行颜色:" << tableWidget->alternatingRowColors();
    qDebug() << "总行数:" << tableWidget->rowCount() << "总列数:" << tableWidget->columnCount();

    // 检查几个单元格的颜色
    for (int row = 0; row < qMin(3, tableWidget->rowCount()); ++row) {
        for (int col = 0; col < qMin(3, tableWidget->columnCount()); ++col) {
            QTableWidgetItem *item = tableWidget->item(row, col);
            if (item) {
                QColor bgColor = item->backgroundColor();
                qDebug() << QString("单元格[%1,%2]: 文本='%3', 背景色=%4, 前景色=%5")
                            .arg(row).arg(col)
                            .arg(item->text())
                            .arg(bgColor.name())
                            .arg(item->foreground().color().name());
            }
        }
    }

    // 进度对话框
    QProgressDialog progress("正在导出Excel文件...", "取消", 0, tableWidget->rowCount() + 2, nullptr);
    progress.setWindowModality(Qt::WindowModal);
    progress.setMinimumDuration(0);
    progress.setValue(0);
    QApplication::processEvents();

    try {
        progress.setLabelText("正在初始化...");
        progress.setValue(1);
        QApplication::processEvents();

        QXlsx::Document xlsx;

        // 写入表头
        progress.setLabelText("正在写入表头...");
        for (int col = 0; col < tableWidget->columnCount(); ++col) {
            QTableWidgetItem *header = tableWidget->horizontalHeaderItem(col);
            QString headerText = header ? header->text() : QString("列%1").arg(col + 1);

            QXlsx::Format format;
            format.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
            format.setVerticalAlignment(QXlsx::Format::AlignVCenter);
            format.setBorderStyle(QXlsx::Format::BorderThin);

            // 复制表头样式
            if (header) {
                // 字体
                QFont font = header->font();
                format.setFontBold(font.bold());
                format.setFontItalic(font.italic());
                if (font.pointSize() > 0) format.setFontSize(font.pointSize());
                if (!font.family().isEmpty()) format.setFontName(font.family());

                // 下划线
                if (font.underline()) {
                    format.setFontUnderline(QXlsx::Format::FontUnderlineSingle);
                }

                // 文字颜色 - 获取表头原来的文字颜色
                QColor fgColor = header->foreground().color();
                if (fgColor.isValid()) {
                    format.setFontColor(fgColor);
                } else {
                    // 如果前景色无效,使用默认黑色
                    format.setFontColor(Qt::black);
                }

                // 背景颜色 - 获取表头原来的背景颜色
                QColor bgColor;

                // 方法1:检查background()
                QBrush bgBrush = header->background();
                if (bgBrush.style() != Qt::NoBrush) {
                    bgColor = bgBrush.color();
                    if (bgColor.isValid() && bgColor != Qt::transparent) {
                        format.setPatternBackgroundColor(bgColor);
                    }
                }

                // 方法2:检查通过setData设置的颜色
                if (!bgColor.isValid() || bgColor == Qt::transparent) {
                    QVariant bgData = header->data(Qt::BackgroundRole);
                    if (bgData.isValid() && bgData.canConvert<QBrush>()) {
                        QBrush dataBrush = bgData.value<QBrush>();
                        if (dataBrush.style() != Qt::NoBrush) {
                            bgColor = dataBrush.color();
                            if (bgColor.isValid() && bgColor != Qt::transparent) {
                                format.setPatternBackgroundColor(bgColor);
                            }
                        }
                    }
                }

                // 方法3:检查textColor/backgroundColor
                if (!bgColor.isValid() || bgColor == Qt::transparent) {
                    bgColor = header->backgroundColor();
                    if (bgColor.isValid() && bgColor != Qt::transparent) {
                        format.setPatternBackgroundColor(bgColor);
                    }
                }

                // 如果没有找到背景色,设置默认浅灰色
                if (!bgColor.isValid() || bgColor == Qt::transparent) {
                    format.setPatternBackgroundColor(QColor(240, 240, 240));
                }

            } else {
                // 没有表头项,使用默认样式(保持与之前一致)
                format.setFontBold(true);
                format.setPatternBackgroundColor(QColor(240, 240, 240));
                format.setFontColor(Qt::black);
            }

            xlsx.write(1, col + 1, headerText, format);
        }

        progress.setValue(2);
        QApplication::processEvents();

        // 定义交替行颜色
        QColor evenRowColor = Qt::white; // 偶数行(从0开始,实际是第1行)
        QColor oddRowColor = QColor(240, 240, 240); // 奇数行

        // 写入数据行(保持不变)
        for (int row = 0; row < tableWidget->rowCount(); ++row) {
            progress.setLabelText(QString("正在写入第 %1/%2 行...").arg(row + 1).arg(tableWidget->rowCount()));

            for (int col = 0; col < tableWidget->columnCount(); ++col) {
                QTableWidgetItem *item = tableWidget->item(row, col);
                QString text = item ? item->text() : "";

                QXlsx::Format format;
                format.setBorderStyle(QXlsx::Format::BorderThin);

                // 默认行背景色(处理交替行)
                QColor defaultRowBgColor = (row % 2 == 0) ? evenRowColor : oddRowColor;

                // 复制单元格样式
                if (item) {
                    // 对齐方式
                    int alignInt = item->textAlignment();
                    Qt::Alignment align = static_cast<Qt::Alignment>(alignInt);

                    // 水平对齐
                    if (align & Qt::AlignLeft) {
                        format.setHorizontalAlignment(QXlsx::Format::AlignLeft);
                    } else if (align & Qt::AlignRight) {
                        format.setHorizontalAlignment(QXlsx::Format::AlignRight);
                    } else if (align & Qt::AlignHCenter) {
                        format.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
                    } else if (align & Qt::AlignJustify) {
                        format.setHorizontalAlignment(QXlsx::Format::AlignHJustify);
                    } else {
                        // 默认对齐方式:检查是否为数字
                        bool isNumber = false;
                        text.toDouble(&isNumber);
                        if (isNumber && !text.isEmpty()) {
                            format.setHorizontalAlignment(QXlsx::Format::AlignRight);
                        } else {
                            format.setHorizontalAlignment(QXlsx::Format::AlignLeft);
                        }
                    }

                    // 垂直对齐
                    if (align & Qt::AlignTop) {
                        format.setVerticalAlignment(QXlsx::Format::AlignTop);
                    } else if (align & Qt::AlignBottom) {
                        format.setVerticalAlignment(QXlsx::Format::AlignBottom);
                    } else if (align & Qt::AlignVCenter) {
                        format.setVerticalAlignment(QXlsx::Format::AlignVCenter);
                    } else {
                        format.setVerticalAlignment(QXlsx::Format::AlignVCenter);
                    }

                    // 字体
                    QFont font = item->font();
                    format.setFontBold(font.bold());
                    format.setFontItalic(font.italic());

                    // 下划线
                    if (font.underline()) {
                        format.setFontUnderline(QXlsx::Format::FontUnderlineSingle);
                    }

                    // 删除线
                    if (font.strikeOut()) {
                        format.setFontStrikeOut(true);
                    }

                    if (font.pointSize() > 0) {
                        format.setFontSize(font.pointSize());
                    }

                    if (!font.family().isEmpty()) {
                        format.setFontName(font.family());
                    }

                    // 文字颜色 - 正确获取方式
                    QColor fgColor = item->foreground().color();
                    if (fgColor.isValid() && fgColor != Qt::black) {
                        format.setFontColor(fgColor);
                    }

                    // 背景颜色 - 关键修复
                    QColor bgColor;

                    // 方法1:检查是否有显式设置的背景色
                    bool hasExplicitBgColor = false;

                    // 检查 background() 方法
                    QBrush bgBrush = item->background();
                    if (bgBrush.style() != Qt::NoBrush) {
                        bgColor = bgBrush.color();
                        if (bgColor.isValid() && bgColor != Qt::transparent) {
                            hasExplicitBgColor = true;
                            qDebug() << QString("单元格[%1,%2]使用background()背景色: %3")
                                        .arg(row).arg(col).arg(bgColor.name());
                        }
                    }

                    // 方法2:检查通过setData设置的颜色
                    if (!hasExplicitBgColor) {
                        QVariant bgData = item->data(Qt::BackgroundRole);
                        if (bgData.isValid() && bgData.canConvert<QBrush>()) {
                            QBrush dataBrush = bgData.value<QBrush>();
                            if (dataBrush.style() != Qt::NoBrush) {
                                bgColor = dataBrush.color();
                                if (bgColor.isValid() && bgColor != Qt::transparent) {
                                    hasExplicitBgColor = true;
                                    qDebug() << QString("单元格[%1,%2]使用data()背景色: %3")
                                                .arg(row).arg(col).arg(bgColor.name());
                                }
                            }
                        }
                    }

                    // 方法3:使用setBackgroundColor设置的颜色
                    if (!hasExplicitBgColor) {
                        bgColor = item->backgroundColor();
                        if (bgColor.isValid() && bgColor != Qt::transparent) {
                            hasExplicitBgColor = true;
                            qDebug() << QString("单元格[%1,%2]使用backgroundColor(): %3")
                                        .arg(row).arg(col).arg(bgColor.name());
                        }
                    }

                    // 设置背景色
                    if (hasExplicitBgColor) {
                        // 使用显式设置的背景色
                        format.setPatternBackgroundColor(bgColor);
                    } else {
                        // 没有显式设置背景色,使用交替行颜色
                        format.setPatternBackgroundColor(defaultRowBgColor);
                    }

                    // 数字格式
                    bool isNumber = false;
                    text.toDouble(&isNumber);
                    if (isNumber && !text.isEmpty()) {
                        // 检查小数位数
                        if (text.contains('.')) {
                            int decimalPlaces = text.length() - text.indexOf('.') - 1;
                            if (decimalPlaces == 0) {
                                format.setNumberFormat("0");
                            } else if (decimalPlaces == 1) {
                                format.setNumberFormat("0.0");
                            } else if (decimalPlaces == 2) {
                                format.setNumberFormat("0.00");
                            } else {
                                format.setNumberFormat("0.000");
                            }
                        } else {
                            format.setNumberFormat("0");
                        }
                    }
                } else {
                    // 单元格没有item,使用默认样式
                    format.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
                    format.setVerticalAlignment(QXlsx::Format::AlignVCenter);
                    format.setPatternBackgroundColor(defaultRowBgColor);
                }

                xlsx.write(row + 2, col + 1, text, format);
            }

            progress.setValue(row + 3);
            QApplication::processEvents();

            if (progress.wasCanceled()) {
                QMessageBox::information(nullptr, "导出取消", "用户取消了导出操作");
                return false;
            }
        }

        // 设置列宽
        progress.setLabelText("正在调整列宽...");
        for (int col = 0; col < tableWidget->columnCount(); ++col) {
            int width = tableWidget->columnWidth(col);
            if (width > 0) {
                int excelWidth = qMax(5, width / 7);
                xlsx.setColumnWidth(col + 1, excelWidth);
            } else {
                xlsx.setColumnWidth(col + 1, 15);
            }
        }

        // 设置行高
        progress.setLabelText("正在调整行高...");
        for (int row = 0; row < tableWidget->rowCount(); ++row) {
            int height = tableWidget->rowHeight(row);
            if (height > 0) {
                int excelHeight = qMax(15, static_cast<int>(height * 0.75));
                xlsx.setRowHeight(row + 2, excelHeight);
            }
        }

        // 保存文件
        progress.setLabelText("正在保存文件...");
        progress.setValue(tableWidget->rowCount() + 2);

        if (xlsx.saveAs(fileName)) {
            qDebug() << "Excel文件保存成功:" << fileName;

            // 询问是否打开文件
            QMessageBox msgBox;
            msgBox.setWindowTitle("导出成功");
            msgBox.setText(QString("Excel文件已保存:\n%1\n\n"
                                  "总计: %2 行 × %3 列\n"
                                  "表格样式已复制到Excel。")
                          .arg(fileName)
                          .arg(tableWidget->rowCount())
                          .arg(tableWidget->columnCount()));
            msgBox.setStandardButtons(QMessageBox::Open | QMessageBox::Ok);
            msgBox.setButtonText(QMessageBox::Open, "打开文件");

            if (msgBox.exec() == QMessageBox::Open) {
                QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
            }

            return true;
        } else{
            // 简化的详细错误提示
            QFile file(fileName);
            QString errorMsg;

            if (file.exists()) {
                // 检查文件是否可写/被占用
                if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
                    errorMsg = QString("保存失败: 文件被其他程序占用\n\n"
                                      "文件: %1\n"
                                      "错误: %2\n\n"
                                      "请关闭正在使用此文件的程序(如Excel),然后重试。\n"
                                      "或者换个文件名保存。")
                              .arg(fileName)
                              .arg(file.errorString());
                } else {
                    file.close();
                    errorMsg = QString("保存失败: 无法覆盖文件\n\n文件: %1").arg(fileName);
                }
            } else {
                // 文件不存在,检查目录权限
                QFileInfo fileInfo(fileName);
                QDir dir = fileInfo.absoluteDir();

                if (!dir.exists()) {
                    errorMsg = QString("保存失败: 目录不存在\n\n目录: %1").arg(dir.path());
                } else {
                    // 检查目录权限
                    QFileInfo dirInfo(dir.path());
                    if (!dirInfo.isWritable()) {
                        errorMsg = QString("保存失败: 没有写入权限\n\n目录: %1").arg(dir.path());
                    } else {
                        errorMsg = QString("保存失败: 无法创建文件\n\n文件: %1").arg(fileName);
                    }
                }
            }

            throw std::runtime_error(errorMsg.toStdString());
        }

    } catch (const std::exception &e) {
        qDebug() << "导出错误:" << e.what();
        QMessageBox::critical(nullptr, "导出失败",
            QString("导出过程中发生错误:\n%1").arg(e.what()));
        return false;
    } catch (...) {
        qDebug() << "导出未知错误";
        QMessageBox::critical(nullptr, "导出失败", "导出过程中发生未知错误");
        return false;
    }
}

运行结果:
在这里插入图片描述

优点:

  • 真正跨平台,不依赖 Excel

  • 生成原生 .xlsx 格式文件

  • 功能丰富,支持单元格格式、公式等


在这里插入图片描述

🎄六、总结

本文详细介绍了四种将 QTableWidget 数据导出到 Excel 的实用方法,同时提供了代码、结果演示,可以根据项目实际需求选择合适的方案。所有方法均已封装成独立函数,只需传入 QTableWidget 对象即可调用,大大简化了开发工作。对于大型数据导出(超过 1000 行),建议添加进度提示和取消功能,避免界面假死。

特性对比CSV 格式制表符分隔QAxObjectQtXlsx
跨平台✅ 全平台✅ 全平台❌ 仅 Windows✅ 全平台
Excel 依赖无需无需需要安装无需
文件格式.csv 文本.xls/.xlsx(文本)原生 .xlsx原生 .xlsx
执行效率⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
功能完整性基础数据基础数据完整功能较完整功能
实现复杂度简单简单中等中等
推荐场景快速导出、兼容性要求高Excel 打开体验好Windows 专属、需要高级功能跨平台、需要原生格式

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

用QT导出Excel表格_qt 导出excel void CreateExcel::outputExcel(TreeNode *p) //输出Excel表格。void CreateExcel::initExcel() //初始化。 阅读详情

相关推荐

qt-- 数据导出到Excel

在Qt自带的axcontainer模块中,我们可以使用QAxObject类来将数据保存到Excel中。Qt中将数据保存到Excel通常有两种方式:一种是以Excel格式导出,需要电脑上安装Office软件;另一种是以CSV格式导出,无需安装Office软件。这里采用第一种方式,实现了UI界面数据的展示、将数据保存到Excel以及将Excel中异常数据标记为红色等功能。数据保存到Excel里(含异常值判断)数据显示(这里用的随机数来表示)

code_snow的博客 5931

QT 数据保存到Excel,并把异常数据标红

在Qt自带的axcontainer模块中,我们可以使用QAxObject类来将数据保存到Excel中。Qt中将数据保存到Excel通常有两种方式:一种是以Excel格式导出,需要电脑上安装Office软件;另一种是以CSV格式导出,无需安装Office软件。这里采用第一种方式,实现了UI界面数据的展示、将数据保存到Excel以及将Excel中异常数据标记为红色等功能。

qq_63538338的博客 2258

qtdesigner使用QTableWidget控件实现读取excel表

qtdesigner使用QTableWidget控件实现读取excel表

fresh_nam的博客 1万+

Qt保存Excel格式数据

本文以一个示例介绍了如何使用 libxlsxwriter 开源库保存QTableWidget表格中的数据到Excel文件。libxlsxwriter 是一个C语言库,可用于将文本、数字、公式和超链接写入Excel 2007以上的excel文件中的多个工作表。它支持的特性非常丰富,如合并单元格、设置字体样式、设置单元格样式、支持图标、支持各种操作系统等,这里就不一一列举了,除此之外它唯一依赖zlib库。

北极星的技术笔记 3916

QT应用编程: 导出QTableWidget数据写入到Execl表格

一、环境介绍 操作系统介绍:win10 64位 QT版本:5.12.6 二、功能介绍 将QTableWidget表格编辑的数据写入到本地execl表格文件中保存。 Header: #include <QAxObject> qmake: QT += axcontainer 三、示例代码 /* 日期: 2020-12-23 作者: DS小龙哥 环境: win10 QT5.12.6 MinGW32 功能: 导出数据到execl表格 */ void Widget::SaveE.

1397

QT导出excel文件。

QT导出EXCEL,从tableWidget列表获取数据导出到excel文件。导出过程使用了excel模板文件,可以从tableWidget读取固定的几列数据导出到excel文件中。其中excel事先设置好文件格式,后续直接读数写数即可。开发过程可以不用关心文件格式,只关注数据。

qtablewidget 导出为 excel

在 Qt 5.2 中使用 OLE 将 qtablewidget 导出为 excel

近山者仁 1万+

qt 界面数据保存到Word文件和Excel文件

Word文件需要模板和设置好书签,通过书签定位到需要修改的位置,把从界面上输入的数据保存到Word文件中。Excel通过类进行输入数据,包括背景色等,随后进行保存。

Qt导出数据到EXCEL的两种方式 (*****)

目录Qt导出数据到EXCEL的两种方式QT将QTableWidget数据保存至ExcelQt如何将数据保存成CSV文件直接保存为 csv文件,可在 excel中打开,简单方便。

ken2232的博客 5759

LTX-2.3 V1.6:8G显存本地AI视频生成工具与int8量化加速实践

这次我们来看一个本地部署的AI视频生成工具——LTX-2.3文字图片生成带音频视频工具V1.6版本。这个工具最大的特点是支持int8量化加速,相比原版提速2-4倍,效果更好,而且8G显存就能运行,不需要搭建复杂环境,解压即可使用。 对于想要在本地电脑上快速生成带音频视频内容的用户来说,这个工具解决了几个关键痛点:首先是硬件门槛低,8G显存意味着大多数主流游戏显卡都能胜任;其次是部署简单,避免了Python环境配置、依赖包冲突等常见问题;最后是性能优化明显,int8加速让生成速度大幅提升。 本文会重点演示如何

hqmln的博客 1233

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码) 文章目录扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)理论讲解KF和EKF模型对比雅可比矩阵计算计算实例应用实例线性模型CV模型:CA模型非线性模型CTRV模型:CTRV实例(python)small demo抛物线demo飞机高度demoC++实例参考文献 我们上篇提到的卡尔曼滤波是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布

O_MMMM_O的博客 10万+

QT常用表格导出为Excel以及Excel导入表格

表格导出为Excel 注意:演示所用到的软件为Qt5.14.2,编译器为MinGW 64-bit,电脑必须装有office 所用的类为 QAxObject,QAxObject可以实例化为一个空对象,使用它应该封装的COM对象的名称,或者使用一个指向表示现有COM对象的IUnknown的指针。如果COM对象实现了IDispatch接口,则该对象的属性、方法和事件将作为Qt属性、槽和信号可用。基类QAxBase提供了通过IUnknown指针直接访问COM对象的API。 简而言之,可以通过QAxObject 来

weixin_42146877的博客 7289

卡方检验的隐藏逻辑:为什么正态分布的平方和如此重要?

本文深入探讨了卡方检验的核心逻辑,揭示了正态分布平方和在统计检验中的重要性。通过分析卡方分布与伽马分布的关系,以及实际应用案例,帮助读者理解卡方检验的原理、局限及高级应用场景,为数据分析提供有力工具。

3a9bq4r8t2y的博客 206

Qt:读取已有数据的Excel文档,并将数据显示在通过QTableWidget绘制的表格中,之后将显示的数据保存成excel格式进行输出(包括表头等内容)

读取已有数据的Excel文档,并将数据显示在通过QTableWidget绘制的表格中,之后将显示的数据保存成excel格式进行输出(包括表头等内容) UI展示及功能简介 读取 //于Mainwindow中,on_read_clicked属于Pushbotton摁键的槽函数 void MainWindow::on_read_clicked() { execel_read();//...

qq_41605114的博客 1万+

OV5640调试大坑,关于binning、RES分辨率与EV曝光

OV5640在使用binning模式时,必须考虑使用场景,分辨率下降叠加动态范围压缩,会使目标对象细节在高光环境下大量丢失,2x2的binning模式,分辨率会远低于感光面积的1/4。

chongyun_的专栏 1822

软件测试——白盒测试实验报告,输入年月日算星期几

软件测试——白盒测试实验报告,输入年月日算星期几,测试用例设计和结果展示

weixin_52278161的博客 2744

QTableWidget导出Excel

1、pro文件中添加如下代码 CONFIG += qaxcontainer 2.头文件中引入 1 #include <QTableWidget> 2 #include <QFileDialog> 3 #include <QDesktopServices> 4 #include <QMessageBox> 5 #include <QAxObject> 3.导出excel方法 //第一个参数是页面上的表格,第二个是导出文件的表头数据

枫影竹韵的博客 1494

【Unity 实用工具篇】 | Unity网格破碎插件 unity-fracture

前面写过一篇Unity中物体破碎效果的插件:【Unity 实用工具篇】 | Unity物体破碎效果 OpenFracture 本文介绍一个另外的工具unity-fracture,也可以实现网格破碎效果,且功能与OpenFracture略有差异。

努力前行,总会成为自己心中的那道光 1万+

轻松实现QT4 QTableWidget与Excel数据交互:一站式教程

轻松实现QT4 QTableWidget与Excel数据交互:一站式教程 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在现代软件开发中,数据的可视化和操作是不可或缺的一部分。QT4作为一款强大的跨平台应用程序开发框架,其QTableWidget控件在数据展示和管理方面具有广泛的应用。然而,如何将QTableWidget与Excel数据进行无缝对接,一直是开发者面临的...

gitblog_09750的博客 896

【异常】安装OpenClaw遇到 Windows环境pnpm安装node-llama-cpp postinstall生命周期脚本执行失败完整解决方案

摘要: Windows环境下使用pnpm安装node-llama-cpp时,postinstall脚本执行失败(错误码3221225477),主要因缺少C++编译工具链或预构建二进制下载失败。解决方案: 基础排查:确保管理员权限、Node.js ≥18、路径无中文; 安装编译工具:推荐Visual Studio的“C++桌面开发”组件或windows-build-tools; 环境变量配置:强制CPU模式+国内镜像(NODE_LLAMA_CPP_FORCE_CPU=true,镜像地址替换为国内源); pnp

奶爸的编程之路,也就一周冷个三天 614

跟踪雷达点迹处理

1,点迹定义: 假设研究对象为位置x和速度v,预测值是根据这一时刻的x值、v值来预测下一时刻的x、v;测量值是根据传感器也就是雷达得到的,因为各种误差的存在,这两个值都不准确,所以把他们加权融合,得到一个新的量—状态值。 点迹就是所谓的测量值,由雷达对同一个目标探测到的一系列点(假设目标静止,但由于误差的存在,会扫描出不止一个点),航迹对应状态值,是点迹和预测轨迹的加权融合。 2,雷达信号和点迹处理关系: 3,点迹航迹处理流程 4,仿真 clear all; RealData=G

wangjie36的博客 1万+

【QT表格-3】QTableWidget导入/导出excel通用代码,不需要安装office,不依赖任何多余环境,甚至不依赖编程语言

导出excel的一种思路,本机不用安装office或者wps,因为它是文本级别的操作,如果excel可以跨平台,这种实现方式可以应用到随便任何一种平台上。只要电子表格支持html格式,它就能用。

大橘子的博客 5575

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

关于QTableWidget数据导出位Excel格式数据

//导出btn槽函数 void MainWindow::SlotExport() { QString filepath = QFileDialog::getSaveFileName(this, tr("Save as..."),QString(), tr("EXCEL files (*.xls);;HTML-Files (*.txt);;")); //获取需要保存的文件路径及文件名称 ...

qq_39526043的博客 932

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

轻松实现QT4 QTableWidget与Excel数据交互:一站式教程推荐

轻松实现QT4 QTableWidget与Excel数据交互:一站式教程推荐 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在现代软件开发中,数据的可视化和操作是不可或缺的一部分。特别是在使用QT4框架开发桌面应用程序时,如何高效地处理和展示数据是一个常见的需求。本项目提供了一个详尽的教程,专注于如何在QT4中使用QTableWidget控件实现Excel数据的导入和...

gitblog_09706的博客 509

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

QT4 QTableWidget 导入、导出 Excel 教程

QT4 QTableWidget 导入、导出 Excel 教程 去发现同类优质开源项目:https://gitcode.com/ 本资源文件提供了一个关于如何在 QT4 中使用 QTableWidget 控件导入和导出 Excel 数据的教程。无论你是初学者还是有一定经验的开发者,这个教程都将帮助你更好地理解和使用 QTableWidget 控件。 资源内容 导入 Excel 数据:详细介绍了如...

gitblog_09709的博客 373
上一篇: 【Qt | QTableWidget】QTableWidget 类的详细解析与代码实践
下一篇: 【Qt | 打包安装包】Windows下使用Inno Setup打包Qt程序成安装包的详细介绍
wkd_007
wkd_007 2024博客之星 TOP 24 2024博客之星 TOP 24 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄12年 11万+粉丝 314原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wkd_007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值