Различные статьи по Qt и c++

Интеграция с Qt Assistant как standalone-справочником: регистрация .qch

Введение

Помимо встраивания справки непосредственно в собственный UI приложения (предыдущая статья), .qch-файл можно открывать в Qt Assistant — отдельном, готовом приложении-справочнике, поставляемом вместе с Qt SDK. Это удобно для продуктов, где полноценная встроенная справочная система избыточна, но всё же нужен удобный, профессионально выглядящий способ просмотра документации — например, для SDK или библиотек, документация которых адресована разработчикам, уже привыкшим к Qt Assistant. В статье разберём оба способа запуска Qt Assistant из своего приложения.

Концепция

Есть два основных режима использования Qt Assistant: standalone-запуск как полностью отдельного процесса (приложение просто открывает Assistant с указанием своего .qch-файла через аргументы командной строки или файл коллекции) и встраиваемый режим через QAssistantClient-подобный механизм (управление запущенным процессом Assistant программно через его удалённый интерфейс stdin/stdout). Первый способ значительно проще в реализации и достаточен для большинства случаев, когда не требуется тонкое программное управление окном Assistant из основного приложения.

Пример кода: Интеграция с Qt

#pragma once
#include <QProcess>
#include <QStandardPaths>
#include <QDebug>

class StandaloneHelpLauncher
{
public:
    explicit StandaloneHelpLauncher(const QString &collectionFilePath)
        : m_collectionFilePath(collectionFilePath) {}

    void showHelp(const QUrl &page = QUrl())
    {
        if (m_process.state() != QProcess::NotRunning) {
            // Assistant уже запущен — отправляем команду навигации
            // через его текстовый протокол на stdin
            if (page.isValid()) {
                sendCommand("setSource " + page.toString());
            }
            sendCommand("activateIdentifier"); // вывести окно на передний план
            return;
        }

        const QString assistantPath = findAssistantExecutable();
        if (assistantPath.isEmpty()) {
            qWarning() << "Qt Assistant не найден в системе";
            return;
        }

        QStringList arguments;
        arguments << "-collectionFile" << m_collectionFilePath
                  << "-enableRemoteControl"; // включаем приём команд через stdin

        m_process.start(assistantPath, arguments);
        if (!m_process.waitForStarted(3000)) {
            qWarning() << "Не удалось запустить Qt Assistant";
            return;
        }

        if (page.isValid()) {
            sendCommand("setSource " + page.toString());
        }
    }

private:
    void sendCommand(const QString &command)
    {
        m_process.write((command + "\n").toUtf8());
    }

    QString findAssistantExecutable()
    {
        // Поиск рядом с самим приложением, либо в стандартных путях
        QString path = QStandardPaths::findExecutable("assistant");
        if (path.isEmpty()) {
            path = QStandardPaths::findExecutable("assistant",
                {QCoreApplication::applicationDirPath()});
        }
        return path;
    }

    QProcess m_process;
    QString m_collectionFilePath;
};
// Использование: кнопка "Справка" в главном меню приложения
#include "standalonehelplauncher.h"

void MainWindow::onHelpActionTriggered()
{
    static StandaloneHelpLauncher launcher(
        QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/myapp_help.qhc");

    launcher.showHelp(QUrl("qthelp://com.mycompany.myapp.1.0/doc/source/getting_started.html"));
}

Пояснения к коду

StandaloneHelpLauncher::showHelp() запускает процесс Qt Assistant с флагом -enableRemoteControl, который активирует простой текстовый протокол управления через стандартный ввод процесса — после запуска приложение может отправлять команды вроде setSource <url> для навигации к конкретной странице или activateIdentifier для вывода окна Assistant на передний план, не перезапуская сам процесс при каждом обращении к справке.

Проверка m_process.state() != QProcess::NotRunning предотвращает повторный запуск нового процесса Assistant при каждом нажатии кнопки «Справка», если он уже открыт — вместо этого повторное обращение просто переключает уже открытое окно на нужную страницу, что соответствует ожидаемому поведению (как, например, повторное открытие уже запущенного приложения операционной системой).

Подводные камни

  • Qt Assistant должен быть либо установлен в системе, либо явно поставляться вместе с приложением. В отличие от встроенного через QHelpEngine варианта (предыдущие статьи), который не требует ничего, кроме самого Qt SDK runtime, standalone Assistant — отдельный исполняемый файл, который нужно либо включить в дистрибутив приложения (что увеличивает размер пакета), либо рассчитывать на его наличие в системе (ненадёжное предположение для конечных пользователей, не разработчиков).
  • Текстовый протокол управления через stdin недокументирован столь же подробно, как основной API QHelpEngine, и его конкретный набор команд может незначительно отличаться между версиями Qt — перед использованием в продакшене стоит протестировать совместимость с конкретной версией Assistant, поставляемой с используемой версией Qt.
  • Аварийное завершение процесса Assistant пользователем (закрытие через системный диспетчер задач, а не через штатное закрытие окна) оставляет QProcess в состоянии, для которого проверка state() может не сразу отразить реальную недоступность процесса — следующая попытка отправить команду через sendCommand() в этом случае не вызовет ошибки явно, но и не произведёт видимого эффекта.
  • Использование standalone Assistant для конечных пользователей непрограммистского продукта может создавать диссонанс в восприятии — окно справки выглядит как «ещё одно приложение Qt SDK», а не часть единого фирменного интерфейса продукта; для продуктов с акцентом на UX обычным конечным пользователям обычно предпочтительнее встроенный вариант справки (статья про QTextBrowser/QWebEngineView), а standalone Assistant больше подходит для развивающих/SDK-инструментов, ориентированных на разработчиков.