Using QtHelp to Lend a Helping Hand
Материал из Wiki.crossplatform.ru
Qt Quarterly | Выпуск 28 | Документация |
by David Boddie
Just as libraries like Qt are not complete without reference guides and API documentation, end user applications need to be distributed with manuals and online help. In their quest to assist with all aspects of the development experience, the developers of Qt's tools have provided a solution that you can use to keep your users informed.
Содержание |
Qt 4.4 introduced so many new features for a minor release that one of them may have escaped many people's notice. The QtHelp module replaces the QtAssistant module of previous versions by providing a mechanism to integrate the Qt Assistant application into applications, but it provides so much more than this.
In this article, we aim to cover some of the new features of the QtHelp module by providing online help for a simple application that happens to feature a scripting interface. As a result, we need to create some API documentation in addition to a user manual, so we will begin by looking at this problem.
Начало работы с API Документации
Пример, который мы используем в этой статье - это простое приложение для обработки изображений, that exposes a single class, ImageWrapper, to Qt Script so that users can write small scripts to process images. All the source and header files for the example can be found in the imageprocessor directory.
Although the class isn't provided in a library, we can document it in just the same way that we document a library like Qt. For simplicity, we only document this class, inserting basic documentation in C-style comments like the following:
/** Scales the image by the horizontal and vertical factors specified by \a xScale and \a yScale respectively. If \a publish is true, the imageChanged() signal will be emitted to notify other components that the image has been changed. */ void ImageWrapper::scale(qreal xScale, qreal yScale, bool publish) { image = image.scaled(int(xScale*image.width()), int(yScale*image.height())); if (publish) emit imageChanged(image); }
To convert this to a form that users can read, we use Doxygen, an open source tool much like the tool used to generate Qt's HTML documentation, but first we must configure it so that it knows which classes to document. Fortunately, Doxygen is supplied with a tool called doxywizard that guides us through the process.
We click the Wizard... button to begin the process of entering the name of our project, the location of our source files and the output directory for the generated HTML documentation — we choose to place the output within the doc directory. The tabs contain options that we can tweak to customize the output, but we prefer to switch off many of the extra features.
The tool lets us save the configuration — we specify a file called Doxyfile in the example's doc directory — and allows us to select a working directory before running Doxygen itself. Some developers may prefer to run Doxygen at the command line from within the doc directory in the following way:
doxygen Doxyfile
In our case, Doxygen creates an html directory within the doc directory and places the documentation in there. Users can read this with a regular Web browser, but we also want to make this available from within the application itself, and this means that we first need to make it available to Qt Assistant.
HTML файлы и проекты помощи
В версиях Qt ранее чем Qt 4.4, Qt Assistant работал с коллекциями HTML-файлов и индексными файлами, подобными qt.dcf, которые описывали содержимое Qt Reference Documentation. В Qt 4.4 и старше, Qt Assistant использует отличный формат файла для его файлов справки, основный на файлах БД SQLite.
Набор инструментов, используемый для сборки документации Qt, выполняет преобразование между массой различных файлов с почти идентичными суфиксами. Таблица ниже описывает, для чего каждый из них используется.
Исходник | Двоичный | Описание |
---|---|---|
.qhp | .qch | Содержит "содержание", индекс элементов в документации, anda file manifest. |
.qhcp | .qhc | Содержит информацию, которая используется, чтобы настроить поведение и доступные возможности Qt Assistant. |
Чтобы создать документацию, отображающуюся в Qt Assistant, мы напишем файл проекта справки Qt - Qt Help Project file - XML-файл с расширением .qhp и "компилируем" его в двоичный сжатый файл справки Qt - Qt Compressed Help file - файл с расширением .qch, используя инструмент qhelpgenerator. Doxygen способен создавать .qhp-файлы, но он может также создавать автоматически .qch-файлы, позволяя нам создавать файлы, которые мы можем использовать прямо с Qt Assistant.
We use the latest version of Doxygen from the project's Subversion repository to create HTML files:
https://doxygen.svn.sourceforge.net/svnroot/doxygen/trunk
You will need to check this out into a new directory, configure it, and build it. We could use a package for Doxygen 1.5.7.1, but the latest sources contain several useful improvements.
For our documentation set, we need to change the Doxyfile configuration file and run Doxygen again. We locate the lines containing GENERATE_QHP, QCH_FILE and other related definitions, and we modify them to look like the following:
GENERATE_QHP = yes QHP_NAMESPACE = "com.trolltech.qq.imageprocessor" QHP_VIRTUAL_FOLDER = "imageprocessor-0.1" QCH_FILE = "../../imageprocessor/help/imageprocessor.qch" QHG_LOCATION = "qhelpgenerator"
Now, we run Doxygen as described above to produce a .qch file. The doc directory contains an html subdirectory as before, but an imageprocessor.qch file has been created within the imageprocessor/help directory — the QCH_FILE declaration contains a path relative to the output directory.
The imageprocessor.qch file must be registered with Qt Assistant before its documentation set can be viewed. You can either open Assistant's Edit"|"Preferences... dialog and add the file to the list of documentation sets or, in the imageprocessor directory, simply type the following at the command line:
assistant -register help/imageprocessor.qch
Since the HTML files, indexes and table of contents are all contained in this one file, you can install it where you like.
Although we don't define them in our example, Doxygen can also be configured to create custom filters for the documentation, as described in the QtHelp module documentation. The definitions for this feature use the following configuration variables:
QHP_CUST_FILTER_NAME QHP_CUST_FILTER_ATTRS QHP_SECT_FILTER_ATTRS
The Doxyfile included with the example code for this article should produce everything that we need for our application.
Profiles and Streamlining Documentation
One way to provide access to our documentation is to open Qt Assistant from within our application and control it using its remote control feature. This is covered by the Simple Text Viewer Example that is distributed with Qt. You can get a feel for the possibilities of this approach by registering the imageprocessor.qch file with Assistant, as described above, and invoking it with the -enableRemoteControl option:
assistant -enableRemoteControl hide contents; hide index; hide bookmarks; hide search; setSource qthelp://com.trolltech.qq.imageprocessor/imageprocessor-0.1/index.html;
We can customize the user interface and available documentation sets by using a Qt Help Collection (.qhc) file. This is the preferred way to use Qt Assistant as a help viewer for an application because it ensures that only the relevant help is shown. Once again, we refer the reader to the Simple Text Viewer Example for information on using .qhc files with Assistant.
For deeper integration, we turn to the classes in the QtHelp module itself, and here we need to create a .qhc file before we can proceed. To do this, we write a Qt Help Collection Project (.qhcp) file which will be compiled to give us a help collection.
The imageprocessor.qhcp file looks like this:
<?xml version="1.0" encoding="UTF-8"?> <QHelpCollectionProject version="1.0"> <assistant> <startPage>qthelp://com.trolltech.qq.imageprocessor/ imageprocessor-0.1/classImageWrapper.html</startPage> </assistant> <docFiles> <register> <file>../imageprocessor/help/imageprocessor.qch</file> </register> </docFiles> </QHelpCollectionProject>
Many additional settings can be added to customize the collection for use with Qt Assistant, but these are not relevant if it is going to be used directly in our application. A compiled collection file can be created with the qcollectiongenerator tool, supplied with Qt:
qcollectiongenerator doc/imageprocessor.qhcp \ -o doc/imageprocessor.qhc
You can test the collection by running Qt Assistant with the-collectionFile option:
assistant -collectionFile doc/imageprocessor.qhc
This should show whether or not the collection is correct.
Integrating Documentation into the Application
We would like to be able to give users access to documentation from within the user interface of our application. To do this, we first need to set up the help system and load the imageprocessor.qhc help collection file. We also need to display the HTML in a browser — for convenience, we simply subclass QTextBrowser and extend it with functionality to access the help collection.
Let's take a look at the code to set up the help engine and lay out the user interface, which we execute in the constructor of our application's main window:
QHelpEngine *helpEngine = new QHelpEngine(DOCS_PATH, this); helpEngine->setupData();
The DOCS_PATH macro is something that we define in the build system for the application — it contains the installed location of the imageprocessor.qhc file. The help engine loads this file, and we ensure it is set up before use.
Остальная часть этого кода создаёт прикрепляемый виджет, который содержит оглавление, предоставляемый как QHelpContentWidget механизмомом справки, и пользовательский виджет просмотрщика текста, который "знает справочную систему".
helpWindow = new QDockWidget(tr("Help"), this); QSplitter *helpPanel = new QSplitter(Qt::Horizontal); HelpBrowser *helpBrowser = new HelpBrowser(helpEngine); helpPanel->insertWidget(0, helpEngine->contentWidget()); helpPanel->insertWidget(1, helpBrowser); helpPanel->setStretchFactor(1, 1); helpWindow->setWidget(helpPanel); addDockWidget(Qt::BottomDockWidgetArea, helpWindow); ... connect(helpEngine->contentWidget(), SIGNAL(linkActivated(const QUrl &)), helpBrowser, SLOT(setSource(const QUrl &)));
We connect these two widgets via the linkActivated() signal so that the user can view topics by double clicking them in the table of contents.
The help browser is simply a subclass of QTextBrowser that can handle the qthelp:// URLs used by the help engine. The relevant part of its implementation is the loadResource() function, which uses the QHelpEngine instance passed on construction to retrieve data for the browser.
QVariant HelpBrowser::loadResource(int type, const QUrl &url) { if (url.scheme() == "qthelp") return QVariant(helpEngine->fileData(url)); else return QTextBrowser::loadResource(type, url); }
For all other URLs, it simply uses the default implementation provided by QTextBrowser.
In the example code accompanying this article, we have put together a simple build system that generates the documentation using Doxygen and creates a help collection with Qt's qcollectiongenerator tool.
The imageprocessor.qch and imageprocessor.qhc files produced by this process are "installed" within the source directory for the example application, and it is this location that is passed as the DOCS_PATH macro to the compiler when building the application.
Adding User Guides and Online Help
Although Doxygen is primarily used for API documentation, it can also be used to create manual pages that can be included in the help collection along with the scripting documentation. Alternatively, we could use a different set of tools to generate HTML documentation and create a separate help collection; QHelpEngine is designed to handle multiple collections, so we would just need a way to present both tables of contents together.
The help engine provides mechanisms to allow individual pages of documentation to be referenced by their "qthelp://" URLs, but it also exposes a search engine, powered by the CLucene indexing library, which can itself be made available to users via the QHelpSearchQueryWidget and QHelpSearchResultWidget classes. Developers typically obtain these widgets via the default QHelpSearchEngine instance provided by the help engine and insert them into the user interface in the same way we used with the QHelpContentWidget instance.
Having the underlying models for the table of contents and documentation index can also be useful for applications that need to expose documents for specific features via certain user interface elements, such as menu items and toolbar buttons. The application can respond to these when they are activated or pressed and retrieve the data directly from the help engine.
More specialized uses of the help system could involve using help collections to store text for tooltips and other forms of online help — with enough time to experiment, plenty of ways can be found to use this source of indexed data.
Further Reading and Resources
The following links should help you get started with the process of documenting your own libraries and applications.
Doxygen can be obtained from the project's Web site:
http://www.stack.nl/~dimitri/doxygen/
The latest version of Doxygen contains code to generate help project and compressed help files as a result of work done on the now-obsolete doxygen2qthelp tool, described in a Qt Labs blog from earlier in the year:
http://labs.trolltech.com/blogs/2008/06/20/
A good place to start reading about the QtHelp module is its page in the Qt documentation:
http://doc.trolltech.com/4.4/qthelp.html
The source code for the example described in this article can be obtained from the Qt Quarterly Web site.
Thanks to Sebastian Pipping for his last minute corrections and suggestions for this article and example code.