1.tableView導出到excel
?點擊導出函數按鈕、發送sendMessage信號(信號名稱,對象,數據)
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
?
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);
#elsets.setEncoding(QStringConverter::System);
#endifQHeaderView* 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;
}
?代碼分析:
#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);
#elsets.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,都為了讓文件編碼正確。
// 按視覺順序排序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 就會按照用戶看到的順序排列,而不是物理順序。常見“坑”提示:
如果你直接用物理順序導出數據,用戶看到的列順序和導出的順序可能不一致。用這段代碼可以保證導出順序和界面一致,體驗更好
?
?