Qt C++中实现文件名按整数序列自然排序的问题求助
Qt实现文件名自然排序(QListWidget)
默认QListWidget的排序是字典序,会导致image1.png、image10.png、image100.png这类不符合数字逻辑的排序结果。要实现按文件名中数字递增的自然排序,可通过以下两种方式解决:
方法一:先对QStringList进行自然排序再添加到列表
- 定义自然排序的比较函数,提取文件名中的数字部分进行比较:
bool naturalSort(const QString &a, const QString &b) { // 提取文件名(不含后缀) QString nameA = a.split('.').first(); QString nameB = b.split('.').first(); // 匹配文件名中的数字序列 QRegularExpression numRegex(R"(\d+)"); QRegularExpressionMatch numMatchA = numRegex.match(nameA); QRegularExpressionMatch numMatchB = numRegex.match(nameB); int numA = numMatchA.hasMatch() ? numMatchA.captured().toInt() : 0; int numB = numMatchB.hasMatch() ? numMatchB.captured().toInt() : 0; // 先按数字大小排序,数字相同则按原字符串字典序 if (numA != numB) { return numA < numB; } return a < b; }
- 修改原代码,收集完所有文件名后执行排序,再添加到QListWidget:
void QtWidgetsApplication::displayImagesList() { // 注意路径中的反斜杠需要转义,或使用正斜杠 QDirIterator it(QStringLiteral("C:\\Users\\Documents\\Visual Studio 2015\\Projects\\cas\\images"), QStringList() << "*.png", QDir::Files, QDirIterator::Subdirectories); QStringList faList; while (it.hasNext()) { QFileInfo file(it.next()); faList.append(file.fileName()); _files.push_back(file.fileName()); } // 对文件名列表执行自然排序 std::sort(faList.begin(), faList.end(), naturalSort); ui.images->addItems(faList); ui.images->setSortingEnabled(true); ui.images->setMinimumWidth(ui.images->sizeHintForColumn(0)); }
方法二:给QListWidget设置自定义排序代理
通过继承QSortFilterProxyModel重写排序规则,让列表控件直接支持自然排序:
- 定义自定义代理类:
#include <QSortFilterProxyModel> #include <QRegularExpression> class NaturalSortProxyModel : public QSortFilterProxyModel { Q_OBJECT protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const override { QString leftStr = sourceModel()->data(left).toString(); QString rightStr = sourceModel()->data(right).toString(); QString nameLeft = leftStr.split('.').first(); QString nameRight = rightStr.split('.').first(); QRegularExpression numRegex(R"(\d+)"); QRegularExpressionMatch numMatchLeft = numRegex.match(nameLeft); QRegularExpressionMatch numMatchRight = numRegex.match(nameRight); int numLeft = numMatchLeft.hasMatch() ? numMatchLeft.captured().toInt() : 0; int numRight = numMatchRight.hasMatch() ? numMatchRight.captured().toInt() : 0; if (numLeft != numRight) { return numLeft < numRight; } return leftStr < rightStr; } };
- 在列表初始化时设置代理:
void QtWidgetsApplication::displayImagesList() { QDirIterator it(QStringLiteral("C:\\Users\\Documents\\Visual Studio 2015\\Projects\\cas\\images"), QStringList() << "*.png", QDir::Files, QDirIterator::Subdirectories); QStringList faList; while (it.hasNext()) { QFileInfo file(it.next()); faList.append(file.fileName()); _files.push_back(file.fileName()); } ui.images->addItems(faList); // 创建并设置排序代理 NaturalSortProxyModel *sortProxy = new NaturalSortProxyModel(this); sortProxy->setSourceModel(ui.images->model()); ui.images->setModel(sortProxy); ui.images->setSortingEnabled(true); ui.images->sortItems(Qt::AscendingOrder); ui.images->setMinimumWidth(ui.images->sizeHintForColumn(0)); }
注意事项
- 路径中的反斜杠必须转义(写成
\\),或直接使用正斜杠/避免转义问题; - 若文件名包含多段数字,可扩展比较函数以支持多段数字的依次比较;
- Qt 5及以上版本推荐使用
std::sort替代qSort。
内容的提问来源于stack exchange,提问作者Cassey
相关产品推荐
相关产品推荐

