Qt help Assistant需要的.qch格式帮助文档制作软件

说明

Qt官方的制作文档非常详细,而且可以搜索文件内容,格式为*.qch,如果直接双击打开的话实际上是sqlite3数据库文件。开发OpenCV时需要查找函数资料,在线和离线的不太方便。所以,我打算制作一个参考文档快速批量制作软件。

qch文件制作是先将参考文档按照目录制作*.qhp文件,如何使用Qt自带软件qhelpgenerator生成qch文件。

qhp格式为XML,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="GB2312"?>
<QtHelpProject version="1.0">
<namespace>bookmisClient.myhelp</namespace>
<virtualFolder>doc</virtualFolder>
<filterSection>
<toc>
<section title="首页" ref="./demoHtml/index.html">
<section title="用户登录" ref="./demoHtml/userlogon.html"></section>
<section title="书籍查询" ref="./demoHtml/bookquery.html"></section>
<section title="续借书籍" ref="./demoHtml/Renewal.html"></section>
<section title="系统管理" ref="./demoHtml/systemmanage.html"></section>
<section title="日志管理" ref="./demoHtml/log.html"></section>
<section title="关于" ref="./demoHtml/about.html"></section>
</section>
</toc>
<keywords>
<keyword name = "登录" ref="./demoHtml/userlogon.html"></keyword>
<keyword name = "续借" ref="./demoHtml/Renewal.html"></keyword>
<keyword name = "日志" ref="./demoHtml/log.html"></keyword>
</keywords>
<files>
<file>demoHtml/*.html</file>
<file>image/*.png</file>
</files>
</filterSection>
</QtHelpProject>

重要的有三部分,files部分就是把文件按照目录方式添加进来。keyword部分是关键词部分,用于搜索。section部分是Qt assistant打开是显示的目录结构。title和name部分可以直接使用文件名,而且只能是HTML文件。
那么文件开发流程是:
1、创建XML格式数据并驻留内存
2、遍历文件夹,对于每个文件转到3
3、提取每个文件的相对于基本目录的路径
4、提取文件名(不包括格式后缀)
5、如果是HTML文件,则添加keyword、section、files模块数据
6、如果不是HTML格式,只添加files模块数据
7、遍历完成,保存数据到文件*.qhp
8、执行qprocess语句qhelpgenerator a.qhp -o b.qch
9、执行完毕
然后就可以使用qch格式文件了。
代码写完之后,发现就是简单的XML格式开发。

开发与解析

首先创建一个空白的Qt widget项目。

Url栏显示需要制作帮助文档的文件目录,通过Folder按钮获取

1
2
3
4
basePath = QFileDialog::getExistingDirectory(this,tr("Open"),fileFullPath);
if(basePath.isEmpty()) return;//如果没有选择文件夹就退出
ui->lineUrl->setText(basePath);//将获取的文件夹地址显示出来
ui->lineResultPath->setText(basePath);//默认*.qch文件输出位置与源文件同位置

Result栏显示*.qch格式文件存放位置,上一步是文件夹(比如:/home/jackey/opencv/4.3.0/),我们需要指定文件名(比如:/home/jackey/opencv/4.3.0/opencv.qch)。可以直接输入,也可以通过Open按钮选择

1
2
3
4
5
ui->lineResultPath->clear();
QString resultPath = QFileDialog::getOpenFileName(this,tr("Open"),fileFullPath);
if(resultPath.isEmpty()) return;//没有选择就退出
resultFullPath = resultPath;//全局变量,保存文件的时候会用到
ui->lineResultPath->setText(resultPath);//显示在界面上

namespace栏是指定之前提到的XML模板文件<namespace></namespace>中间的文字,填什么就是什么)。

下面的文本框是日志部分,用于输出每个阶段的运行结果。

根据之前的开发流程,先遍历文件夹里面的所有文件,如果是HTML格式就添加keyword字段和section字段,同时将遍历的所有格式文件都添加到files字段中。
在正式获取文件夹中文件之前,应该先有XML格式的文件,如何按照规则写入数据就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool MainWindow::initXML()
{
QDomProcessingInstruction instruction;
instruction=doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
doc.appendChild(instruction);

QDomElement root = doc.createElement("QtHelpProject");
root.setAttribute("version","1.0");
doc.appendChild(root);

QDomElement ns=doc.createElement("namespace");
QDomText text=doc.createTextNode(ui->lineNamespace->text());
ns.appendChild(text);
root.appendChild(ns);

QDomElement vf = doc.createElement("virtualFolder");
QDomText vfText = doc.createTextNode("doc");
vf.appendChild(vfText);
root.appendChild(vf);

QDomElement fs = doc.createElement("filterSection");
QDomElement toc = doc.createElement("toc");
//索引内容
fs.appendChild(toc);
QDomElement kw = doc.createElement("keywords");
//关键词
fs.appendChild(kw);
QDomElement files = doc.createElement("files");
//所有文件
fs.appendChild(files);
root.appendChild(fs);

log("The basic structure is completed!");//显示在界面的日志

return true;
}

此XML初始化函数执行完毕后,可以得到一个没有数据只是个模板的qhp文件。
执行结果如下

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="GB2312"?>
<QtHelpProject version="1.0">
<namespace>从界面获取</namespace>
<virtualFolder>从界面获取</virtualFolder>
<filterSection>
<toc></toc>
<keywords></keywords>
<files></files>
</filterSection>
</QtHelpProject>

这是一个基本框架,只要把数据填入,就可以生成qch格式文件了。

递归获取文件夹下文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void MainWindow::findAllFiles(QString dirPath)
{
if(dirPath.isEmpty()) return;//路径为空就退出
QDir dir(dirPath);
QFileInfoList fileInfoList = dir.entryInfoList();
foreach(QFileInfo fileInfo , fileInfoList){
if(fileInfo.fileName() == "."||fileInfo.fileName()==".."){//过滤Linux文件系统的. 和..文件夹
continue;
}
else if(fileInfo.isDir()){
findAllFiles(fileInfo.filePath());//递归获取文件夹和文件
dirCnt++;//计数
}
else if(fileInfo.isFile()){//如果是文件就开始进行格式过滤,如果是目录就继续深入
bool isValid = false;
if(fileInfo.suffix()=="html") isValid=true;//表示此文件是HTML格式
QString crtFilePath = fileInfo.filePath();//文件完整路径
QString content = crtFilePath.remove(basePath+QDir::separator());//获取相对路径
QString title = fileInfo.fileName().split(".").at(0);//获取无格式的文件名
QString name=title;
addFilesNode(isValid,title,name,content);//将数据写入节点
fileCnt++;
}
}
}

将填入数据的XML格式文件写入qhp格式文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool MainWindow::save2file(QString dstPath)
{
if(dstPath.isEmpty()) throw "There must has dstination file path!";
QFile file(dstPath);
if(!file.open(QFile::WriteOnly)){
file.close();
return false;
}

QTextStream writeOut(&file);
doc.save(writeOut,4);//缩进4字符
file.close();

log("All data has been saved!");
return true;
}

然后调用qhelpgenerator进行编译

1
2
3
4
5
6
7
8
9
10
11
bool MainWindow::generateQch()
{
QString cmd = QString("qhelpgenerator %1 -o %2")
.arg(resultFullPath)
.arg(dstFullPath);
QProcess pro;
pro.start(cmd,QProcess::ReadWrite);
pro.waitForFinished();
log(pro.readAllStandardOutput());
return true;
}

就会生成qch格式文件了。

编译运行

编译,运行,选择文档的父目录,然后生成。

TODO

只是简单的遍历文件夹,无法生成树形结构的参考文档。

参考资料


Qt help Assistant需要的.qch格式帮助文档制作软件
https://blog.jackeylea.com/qt/qt-help-assistant-qch-doc-creator/
作者
JackeyLea
发布于
2020年4月12日
许可协议