使用QDirModel替换目录名称中的中文数字
一、 需求
经常会有一些教程,其目录名是用中文显示的,比如:“第一讲”、“第二讲”、"第三讲"之类的,这时目录排序的时候以汉字的编码进行排序,如下所示:
E:.
├─第一讲
├─第三讲
└─第二讲
这种顺序是难以理解的,于是想到把这种中文数字替换成阿拉伯数字:“一二三四五六七八九十” --> “1234567890”。
E:.
├─第01讲
├─第02讲
└─第03讲
上面这种顺序就很直观,看着赏心悦目一点。
二、核心算法–替换中文数字
算法倒是简单,简单的查找替换,并依次生成一个整数即可。
QString chineseNumber = "一二三四五六七八九十";
- 获取一个字符串 txt = “第一十二讲”
- 迭代每一个字符 charTmp = txt.at(i)
- 在chineseNumber中查找charTmp,获取 index = QString::indexOf(charTmp )
- 记录起始索引 start = index
- “一十二” ,这是常规的替换
- 查找到 “一” : num += index(‘一’) + 1, len += 1;
- 查找到 “十” : num *= 10, len += 1;
- 查找到 “二” : num += index(‘二’) + 1, len += 1;
- “十二” ,但是在中文里面 ‘十’ 可以单独放在前面的,所以需要在上面的算法中加判断
- 查找到 “十” :如果len==0,那么num += index(‘十’) +1,否则的话 num *= 10, len += 1;
- 查找到 “二” : num += index(‘二’) + 1, len += 1;
- 替换字符串操作: QString &QString::replace(int start, int len, const QString &after)方法
具体实现
int len = 0;
int num = 0;
int start = 0;
for (int i = 0; i < txt.length (); ++i) {
auto index = chineseNumber.indexOf (txt.at (i),i);
// 找到第一个中文数字
if(index != -1){
if(len==0)
start = i;
if(index>=9 && len != 0){
num *=10;
} else{
num += index+1;
}
len += 1;
}
}
if(len>0) {
txt.replace (start,len,QString("%1").arg (num,2,10,QChar('0')));
}
三、添加个界面
如果不用界面,开发就算到此为止,很简单,目录名的替换直接用 QDir::rename(const QString &oldName, const QString &newName)
实现方法太多也是挺让人愁的,最终敲定的结果是 用 QTreeView + QDirModel 来实现。
又发现 QDirModel 的 setData 方法可以直接修改目录名称,这不是又能偷懒了么
bool QDirModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_D(QDirModel);
if (!d->indexValid(index) || index.column() != 0
|| (flags(index) & Qt::ItemIsEditable) == 0 || role != Qt::EditRole)
return false;
......
if (dir.rename(node->info.fileName(), name)) {
......
}
QDirModel :: setData 需要 index对应的item具有可编辑设置才行,使用 model->setReadOnly (false);
1. 简单布局
如果只需要显示目录,model 添加过滤器 model->setFilter (QDir::Dirs | QDir::NoDotAndDotDot) ;
2. Open按钮的clicked槽函数
-
点击按钮弹出目录选择对话框
QFileDialog::getExistingDirectory (this,"选择目录",curPath,QFileDialog::DontUseNativeDialog);
,当然使用本地对话框也行
-
更新treeView的rootIndex
ui->lineEditPath->setText (selPath); auto rootIndex = model->index (selPath); ui->treeView->setRootIndex (rootIndex);
3. Apply 按钮的clicked槽函数
-
遍历目录节点, 并修改目录名
获取根索引,获取第1个索引,treeView获取下一个索引
// 获取树的根索引 auto rootIndex = ui->treeView->rootIndex (); // 根索引的第一个子索引 auto subIndex = model->index (0,0,rootIndex); while (subIndex.isValid ()) { // 获取 目录名 auto dirname = subIndex.data ().toString (); // 获取 替换中文数字以后的字符串 auto txt = replaceChineseNumber (dirname); // model 设置数据后,会自动对应的目录名 qout << model->setData (subIndex,txt); // 迭代到下一个索引 subIndex = ui->treeView->indexBelow (subIndex); }
四、cpp代码
#include "DirExplorer.h"
#include "ui_DirExplorer.h"
#include <QDebug>
#include <QFileDialog>
#include <QAbstractItemModel>
#include <QStandardPaths>
static QString chineseNumber = "一二三四五六七八九十";
static QString selPath;
DirExplorer::DirExplorer(QWidget *parent) :
QWidget(parent),
ui(new Ui::DirExplorer)
{
ui->setupUi(this);
// model = new QFileSystemModel(this);
model = new QDirModel(this);
model->setReadOnly (false);
// model->setFilter (QDir::Dirs | QDir::NoDotAndDotDot) ;
ui->treeView->setModel (model);
auto index = model->index (QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).at(0));
ui->treeView->setRootIndex (index);
qout << model->columnCount ();
for (int i = 1; i < model->columnCount (); ++i) {
ui->treeView->hideColumn (i);
}
}
DirExplorer::~DirExplorer()
{
delete ui;
}
QString DirExplorer::replaceChineseNumber(QString txt)
{
int len = 0;
int num = 0;
int start = 0;
for (int i = 0; i < txt.length (); ++i) {
auto index = chineseNumber.indexOf (txt.at (i));
// 找到第一个中文数字
if(index != -1){
if(len==0)
start = i;
if(index>=9 && len != 0){
num *=10;
} else{
num += index+1;
}
len += 1;
}
}
if(len>0) {
txt.replace (start,len,QString("%1").arg (num,2,10,QChar('0')));
}
return txt;
}
void DirExplorer::on_toolButtonOpen_clicked()
{
auto curPath = ui->lineEditPath->text ();
if (curPath.isEmpty ())
curPath = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).at(0);
selPath = QFileDialog::getExistingDirectory (this,"选择目录",curPath,QFileDialog::DontUseNativeDialog);
if(selPath.isEmpty ())
return;
ui->lineEditPath->setText (selPath);
auto rootIndex = model->index (selPath);
ui->treeView->setRootIndex (rootIndex);
}
void DirExplorer::on_toolButtonApply_clicked()
{
// 获取树的根索引
auto rootIndex = ui->treeView->rootIndex ();
// 根索引的第一个子索引
auto subIndex = model->index (0,0,rootIndex);
while (subIndex.isValid ()) {
// 获取 目录名
auto dirname = subIndex.data ().toString ();
// 获取 替换中文数字以后的字符串
auto txt = replaceChineseNumber (dirname);
// model 设置数据后,会自动对应的目录名
qout << model->setData (subIndex,txt);
// 迭代到下一个索引
subIndex = ui->treeView->indexBelow (subIndex);
}
}