Qt写入excel

1.tableView导出到excel

点击导出函数按钮、发送sendMessage信号(信号名称,对象,数据)

cpp 复制代码
void HydroelectricPowerPluginImpl::exportTableViewSelectedRows(QTableView* tableView, QWidget* parent)
{
    if (!tableView || !tableView->model())
        return;

    QString fileName = QFileDialog::getSaveFileName(parent, "导出选中行为CSV", "", "CSV文件 (*.csv)");
    if (fileName.isEmpty())
        return;

    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
    QAbstractItemModel* model = tableView->model();

    // 写表头
    QStringList headers;
    for (int col = 0; col < model->columnCount(); ++col) {
        headers << model->headerData(col, Qt::Horizontal).toString();
    }
    out << headers.join(",") << "\n";

    // 写选中行数据
    for (int row = 0; row < model->rowCount(); ++row) {
        QStringList rowData;
        for (int col = 0; col < model->columnCount(); ++col) {
            if (model->data(model->index(row, col)) != QVariant()) {
                rowData << model->data(model->index(row, col)).toString();
            }
            if (model->data(model->index(row, col), Qt::UserRole) != QVariant()) {
                rowData << F0(model->data(model->index(row, col), Qt::UserRole).toInt());
            }
        }
        out << rowData.join(",") << "\n";
    }
    file.close();
}

2.点击button导出tableview

cpp 复制代码
bool Utils::Gui::ExportVisibleColumnsToCSV(QTableView* tableView, const QString& filename, bool delegate, std::function<QString(const QVariant&)> v2s)
{
    QAbstractItemModel* model = tableView->model();
    if (model == nullptr) {
        return false;
    }

    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        return false;
    }

    QTextStream ts(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QTextCodec* codec = QTextCodec::codecForName("UTF-8");
    if (codec) {
        ts.setCodec(codec);
    } else {
        ts.setCodec(QTextCodec::codecForLocale());
    }
    ts.setGenerateByteOrderMark(true);
#else
    ts.setEncoding(QStringConverter::System);
#endif

    QHeaderView* header = tableView->horizontalHeader();
    QList<int> visibleCols;

    for (int col = 0; col < model->columnCount(); ++col) {
        if (delegate || (!header->isSectionHidden(col) && !IsColumnUsingCustomDelegate(tableView, col))) {
            visibleCols.append(col);
        }
    }
    // 按视觉顺序排序
    std::sort(visibleCols.begin(), visibleCols.end(), [header](int a, int b) {
        return header->visualIndex(a) < header->visualIndex(b);
    });
    QStringList headerList;
    for (int col : visibleCols) {
        headerList << EscapeCSV(model->headerData(col, Qt::Horizontal).toString());
    }
    ts << headerList.join(',') << '\n';

    // 写入数据行
    for (int row = 0; row < model->rowCount(); ++row) {
        QStringList rowData;
        for (int col : visibleCols) {
            QModelIndex index = model->index(row, col);
            auto&& v = model->data(index);
            rowData << EscapeCSV(v2s == nullptr ? v.toString() : v2s(index));
        }
        ts << rowData.join(',') << '\n';
    }

    file.close();
    return true;
}







QString Utils::Gui::EscapeCSV(const QString& value)
{
    if (value.contains('"') || value.contains(',') || value.contains('\n') || value.contains('\r')) {
        QString escaped = value;
        escaped.replace("\"", "\"\"");
        return "\"" + escaped + "\"";
    }
    return value;
}

代码分析:

cpp 复制代码
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QTextCodec* codec = QTextCodec::codecForName("UTF-8");
    if (codec) {
        ts.setCodec(codec);
    } else {
        ts.setCodec(QTextCodec::codecForLocale());
    }
    ts.setGenerateByteOrderMark(true);
#else
    ts.setEncoding(QStringConverter::System);
#endif



详细解释
1. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
•	这部分代码只在 Qt 5 及以下版本编译时生效。
•	Qt 5 及以下用 QTextCodec 设置编码。
代码含义:
•	QTextCodec* codec = QTextCodec::codecForName("UTF-8");
尝试获取 UTF-8 编码的 QTextCodec。
•	if (codec) { ts.setCodec(codec); }
如果获取成功,设置 QTextStream 使用 UTF-8 编码。
•	else { ts.setCodec(QTextCodec::codecForLocale()); }
如果失败,则使用系统默认编码。
•	ts.setGenerateByteOrderMark(true);
让输出流在文件开头写入 UTF-8 的 BOM(字节顺序标记),有些软件(如 Excel)读取 CSV 时需要 BOM 才能正确识别为 UTF-8。
2. #else
•	这部分代码只在 Qt 6 及以上版本编译时生效。
•	Qt 6 移除了 QTextCodec,改用 QStringConverter。
代码含义:
•	ts.setEncoding(QStringConverter::System);
设置 QTextStream 使用系统默认编码(通常是 UTF-8)。
 
总结
•	目的:保证导出的 CSV 文件编码为 UTF-8,兼容不同 Qt 版本。
•	"坑"提示:如果编码设置不对,中文等非 ASCII 字符在 Excel 等软件中可能会乱码。
 
简要记忆:
Qt 5 用 QTextCodec,Qt 6 用 QStringConverter,都为了让文件编码正确。
cpp 复制代码
    // 按视觉顺序排序
    std::sort(visibleCols.begin(), visibleCols.end(), [header](int a, int b) {
        return header->visualIndex(a) < header->visualIndex(b);
    });



这行代码的作用是:按照表头的视觉顺序对 visibleCols 进行排序。
详细解释
•	visibleCols 是一个存储可见列索引(int)的列表。
•	header 是 QTableView 的水平表头(QHeaderView*)。
•	header->visualIndex(a) 返回列 a 在界面上显示的位置(比如用户拖动列顺序后,物理列索引和视觉顺序可能不同)。
•	std::sort(..., [header](int a, int b) { ... })
使用 lambda 表达式自定义排序规则:如果 a 的视觉索引小于 b,则 a 排在前面。
举例说明
假设表格有 4 列,物理顺序是 0,1,2,3,但用户把第2列拖到最前面,视觉顺序变成 2,0,1,3。
此时 header->visualIndex(2) 返回 0,header->visualIndex(0) 返回 1,依此类推。
排序后,visibleCols 就会按照用户看到的顺序排列,而不是物理顺序。
 
常见"坑"提示:
如果你直接用物理顺序导出数据,用户看到的列顺序和导出的顺序可能不一致。用这段代码可以保证导出顺序和界面一致,体验更好
相关推荐
哈__1 小时前
MongoDB 平替新方案:金仓多模数据库驱动电子证照国产化落地
数据库·1024程序员节
sulikey2 小时前
Qt 入门简洁笔记:从框架概念到开发环境搭建
开发语言·前端·c++·qt·前端框架·visual studio·qt框架
微学AI2 小时前
国产数据库替代MongoDB的技术实践过程:金仓多模数据库在电子证照系统中的深度应用
数据库·人工智能·1024程序员节
TDengine (老段)2 小时前
TDengine 数据函数 ROUND 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·1024程序员节
TDengine (老段)2 小时前
TDengine 数学函数 RAND 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
野犬寒鸦2 小时前
从零起步学习MySQL || 第十章:深入了解B+树及B+树的性能优势(结合底层数据结构与数据库设计深度解析)
java·数据库·后端·mysql·1024程序员节
GZ_TOGOGO2 小时前
Oracle OCP考试报名常见问题详解
数据库·oracle·ocp认证
睡不醒的猪儿2 小时前
nginx日志同步阿里云datahub后写入数据库
数据库·nginx·阿里云
xie_zhr3 小时前
【PB案例学习笔记】-46在数据窗口中编辑数据
数据库·his·1024程序员节·干货分享·pb·powerbuilder
小小的木头人3 小时前
Redis 集群安装指南
数据库·redis