Skip to content

fix(export): align table header and content in exported TXT file#656

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:develop/eaglefrom
GongHeng2017:202605081139-eagle-fix
May 8, 2026
Merged

fix(export): align table header and content in exported TXT file#656
deepin-bot[bot] merged 1 commit intolinuxdeepin:develop/eaglefrom
GongHeng2017:202605081139-eagle-fix

Conversation

@GongHeng2017
Copy link
Copy Markdown
Contributor

@GongHeng2017 GongHeng2017 commented May 8, 2026

Replace fixed QTextStream::setFieldWidth with display-width-aware padding. Add displayWidth() to calculate CJK characters as 1.5 columns, and use two-pass scanning in EXPORT_TO_TXT to compute per-column max width for accurate alignment.

修复导出TXT文件中表头与内容列不对齐的问题。
用基于显示宽度的空格填充替换固定setFieldWidth方式,
新增displayWidth计算CJK字符为1.5列宽度,
通过两遍扫描计算每列最大宽度实现精确对齐。

Log: 修复导出TXT文件表头与内容列不对齐
Bug: https://pms.uniontech.com/bug-view-357619.html
Influence: 导出TXT文件时,表头和内容的列能正确对齐,中英文混排场景下不再错位。

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @GongHeng2017, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@GongHeng2017 GongHeng2017 force-pushed the 202605081139-eagle-fix branch 3 times, most recently from 6c82524 to 595b1e5 Compare May 8, 2026 08:09
Replace fixed QTextStream::setFieldWidth with display-width-aware
padding. Add displayWidth() to calculate CJK characters as 1.5 columns,
and use two-pass scanning in EXPORT_TO_TXT to compute per-column max
width for accurate alignment.

修复导出TXT文件中表头与内容列不对齐的问题。
用基于显示宽度的空格填充替换固定setFieldWidth方式,
新增displayWidth计算CJK字符为1.5列宽度,
通过两遍扫描计算每列最大宽度实现精确对齐。

Log: 修复导出TXT文件表头与内容列不对齐
Bug: https://pms.uniontech.com/bug-view-357619.html
Influence: 导出TXT文件时,表头和内容的列能正确对齐,中英文混排场景下不再错位。
@GongHeng2017 GongHeng2017 force-pushed the 202605081139-eagle-fix branch from 595b1e5 to 211ad41 Compare May 8, 2026 08:17
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

Git Diff 代码审查报告

1. 整体评估

这段代码主要修改了设备管理器中表格导出到文本文件的功能,改进了列宽计算方式,使其能够更好地处理中文字符的显示宽度。整体上代码逻辑清晰,但在实现细节上存在一些可以优化的地方。

2. 语法逻辑分析

2.1 displayWidth函数

double DeviceBaseInfo::displayWidth(const QString &str)
{
    double width = 0;
    for (const QChar &ch : str) {
        ushort code = ch.unicode();
        // CJK字符占1.5列,其余占1列
        if (code > 0x7E || (code >= 0xA1 && code <= 0xFF))
            width += 1.5;
        else
            width += 1;
    }
    return width;
}

问题

  1. CJK字符范围判断不够精确。当前判断code > 0x7E || (code >= 0xA1 && code <= 0xFF)可能包含一些非CJK字符,也可能遗漏一些CJK字符。
  2. 使用ushort存储Unicode码点,对于超出U+FFFF的字符(如emoji)处理不正确。

改进建议

double DeviceBaseInfo::displayWidth(const QString &str)
{
    double width = 0;
    for (const QChar &ch : str) {
        uint code = ch.unicode();
        // 处理代理对(surrogate pairs)
        if (ch.isHighSurrogate()) {
            continue; // 跳过高代理,等待低代理
        }
        if (ch.isLowSurrogate()) {
            // 代理对字符,通常显示宽度为2
            width += 2;
            continue;
        }
        
        // 更精确的CJK字符范围判断
        if ((code >= 0x4E00 && code <= 0x9FFF) || // CJK统一表意文字
            (code >= 0x3400 && code <= 0x4DBF) || // CJK扩展A
            (code >= 0x20000 && code <= 0x2A6DF) || // CJK扩展B
            (code >= 0x2A700 && code <= 0x2B73F) || // CJK扩展C
            (code >= 0x2B740 && code <= 0x2B81F) || // CJK扩展D
            (code >= 0x2B820 && code <= 0x2CEAF) || // CJK扩展E
            (code >= 0xF900 && code <= 0xFAFF) || // CJK兼容表意文字
            (code >= 0x2F800 && code <= 0x2FA1F)) // CJK兼容表意文字补充
            width += 1.5;
        else
            width += 1;
    }
    return width;
}

2.2 tableInfoToTxt和tableHeaderToTxt函数

问题

  1. tableHeaderToTxt中,循环条件是col < m_TableHeaderTr.size() - 1,而在tableInfoToTxt中是col < m_TableDataTr.size(),两者不一致,可能导致最后一列处理不同。
  2. 没有对colWidths参数进行有效性检查。

改进建议

void DeviceBaseInfo::tableInfoToTxt(QTextStream &out, const QList<double> &colWidths)
{
    // 获取表格内容
    getTableData();
    
    if (m_TableDataTr.isEmpty())
        return;
    
    // 确保colWidths至少有足够的列
    QList<double> safeColWidths = colWidths;
    while (safeColWidths.size() < m_TableDataTr.size()) {
        safeColWidths.append(30.0); // 默认宽度
    }
    
    for (int col = 0; col < m_TableDataTr.size(); ++col) {
        double w = safeColWidths[col];
        int pad = qMax(0, static_cast<int>(w - displayWidth(m_TableDataTr[col])));
        out << m_TableDataTr[col] << QString(pad, ' ');
    }
    out << "\n";
}

void DeviceBaseInfo::tableHeaderToTxt(QTextStream &out, const QList<double> &colWidths)
{
    // 获取表头
    getTableHeader();
    
    if (m_TableHeaderTr.isEmpty())
        return;
    
    // 确保colWidths至少有足够的列
    QList<double> safeColWidths = colWidths;
    while (safeColWidths.size() < m_TableHeaderTr.size()) {
        safeColWidths.append(30.0); // 默认宽度
    }
    
    out << "\n";
    for (int col = 0; col < m_TableHeaderTr.size(); ++col) {
        double w = safeColWidths[col];
        int pad = qMax(0, static_cast<int>(w - displayWidth(m_TableHeaderTr[col])));
        out << m_TableHeaderTr[col] << QString(pad, ' ');
    }
    out << "\n";
}

3. 代码质量分析

3.1 变量命名

  • 宏定义中的变量名使用了下划线前缀(如_hdr, _colCount),这与Qt的命名规范不太一致。Qt通常使用驼峰命名法。
  • 建议改为更符合Qt风格的命名:header, colCount, colWidths, device, data等。

3.2 代码重复

  • tableInfoToTxttableHeaderToTxt中有相似的代码逻辑,可以提取为公共函数:
void DeviceBaseInfo::writeTableRowToTxt(QTextStream &out, const QStringList &rowData, const QList<double> &colWidths)
{
    if (rowData.isEmpty())
        return;
    
    QList<double> safeColWidths = colWidths;
    while (safeColWidths.size() < rowData.size()) {
        safeColWidths.append(30.0);
    }
    
    for (int col = 0; col < rowData.size(); ++col) {
        double w = safeColWidths[col];
        int pad = qMax(0, static_cast<int>(w - displayWidth(rowData[col])));
        out << rowData[col] << QString(pad, ' ');
    }
    out << "\n";
}

4. 代码性能分析

4.1 字符串处理

  • displayWidth函数对每个字符进行迭代,对于长字符串可能有性能影响。
  • 可以考虑缓存字符串的显示宽度,特别是对于重复出现的字符串。

4.2 宏定义中的计算

  • 宏定义中每次导出表格都要重新计算列宽,如果频繁调用可能影响性能。
  • 可以考虑将列宽计算结果缓存,只在数据变化时重新计算。

5. 代码安全分析

5.1 输入验证

  • 缺少对colWidths参数的有效性检查,可能导致数组越界访问。
  • 已在改进建议中添加了安全检查。

5.2 类型转换

  • int pad = qMax(0, int(w - displayWidth(m_TableDataTr[col])));中,从doubleint的转换没有使用static_cast,可能导致编译警告。
  • 已在改进建议中修改为static_cast<int>

6. 其他建议

  1. 考虑使用Qt的QTextDocumentQTextTable来处理表格格式化,这些类提供了更丰富的文本格式化功能。

  2. 对于CJK字符的显示宽度,可以考虑使用Qt的QFontMetrics类来获取更准确的宽度:

double DeviceBaseInfo::displayWidth(const QString &str)
{
    static QFontMetrics fm(QApplication::font());
    return fm.horizontalAdvance(str) / fm.horizontalAdvance('0');
}
  1. 考虑添加单元测试,特别是针对displayWidth函数,确保它能正确处理各种字符。

  2. 在宏定义中,可以考虑添加错误处理机制,如检查deviceLst是否为空,以及getTableHeader()getTableData()是否返回有效数据。

总结

这段代码改进了表格导出功能,使其能够更好地处理中文字符的显示宽度。主要改进点包括:

  1. 添加了displayWidth函数来计算字符串的显示宽度
  2. 修改了tableInfoToTxttableHeaderToTxt函数,使用动态计算的列宽
  3. 在宏定义中添加了列宽计算逻辑

建议的改进主要集中在:

  1. 更精确的CJK字符范围判断
  2. 添加输入验证和错误处理
  3. 减少代码重复
  4. 优化性能
  5. 使用更安全的类型转换

这些改进将使代码更健壮、更高效,并提高其可维护性。

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: GongHeng2017, max-lvs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@GongHeng2017
Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot deepin-bot Bot merged commit 3b4db17 into linuxdeepin:develop/eagle May 8, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants