16.2. Использование QTextBrowser для отображения текста справки.

Большие серьезные приложения могут содержать объем справочной информации, намного превышающий возможности всплывающих подсказок и даже подсказок типа "What's This?". Самое простое решение в этом случае -- создать обозреватель справочной системы. Приложение может открывать окно обозревателя справки при выборе пункта Help, в меню Help, или при нажатии на кнопку Help в панели инструментов.

В этом разделе мы рассмотрим простейший обозреватель справочной системы, внешний вид которого представлен на рисунке 16.3, и опишем, как его использовать в приложении. Для отображения текста справки используется QTextBrowser, который может обрабатывать некоторые теги HTML и идеально подходит под заданные условия.

Рисунок 16.3. Виджет HelpBrowser.


Как обычно, начнем с заголовочного файла: #include <qwidget.h> class QPushButton; class QTextBrowser; class HelpBrowser : public QWidget { Q_OBJECT public: HelpBrowser(const QString &path, const QString &page, QWidget *parent = 0, const char *name = 0); static void showPage(const QString &page); private slots: void updateCaption(); private: QTextBrowser *textBrowser; QPushButton *homeButton; QPushButton *backButton; QPushButton *closeButton; }; HelpBrowser имеет статическую функцию, которая может вызываться из любого места в приложении. Она создает окно обозревателя и показывает запрошенную страницу.

Теперь исходный код файла реализации:

#include <qapplication.h> #include <qlayout.h> #include <qpushbutton.h> #include <qtextbrowser.h> #include "helpbrowser.h" HelpBrowser::HelpBrowser(const QString &path, const QString &page, QWidget *parent, const char *name) : QWidget(parent, name, WGroupLeader | WDestructiveClose) { textBrowser = new QTextBrowser(this); homeButton = new QPushButton(tr("&Home"), this); backButton = new QPushButton(tr("&Back"), this); closeButton = new QPushButton(tr("Close"), this); closeButton->setAccel(tr("Esc")); QVBoxLayout *mainLayout = new QVBoxLayout(this); QHBoxLayout *buttonLayout = new QHBoxLayout(mainLayout); buttonLayout->addWidget(homeButton); buttonLayout->addWidget(backButton); buttonLayout->addStretch(1); buttonLayout->addWidget(closeButton); mainLayout->addWidget(textBrowser); connect(homeButton, SIGNAL(clicked()), textBrowser, SLOT(home())); connect(backButton, SIGNAL(clicked()), textBrowser, SLOT(backward())); connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); connect(textBrowser, SIGNAL(sourceChanged(const QString &)), this, SLOT(updateCaption())); textBrowser->mimeSourceFactory()->addFilePath(path); textBrowser->setSource(page); } Размещение компонентов в окне более чем простое: ряд кнопок находится над QTextBrowser. Аргумент path -- это путь к каталогу, где находятся файлы с текстом справки. Аргумент page -- имя файла справки, с необязательным названием темы (в терминах HTML -- anchor, или имя ссылки).

Мы передаем конструктору флаг WGroupLeader, потому что окно HelpBrowser может открываться из модальных диалогов. Обычно модальные диалоги не позволяют пользователю взаимодействовать с другими окнами приложения. Однако, в данном случае, после того как пользователь запросил помощь, он должен иметь возможность работать как с окном модального диалога, так и с окном обозревателя справочной системы. Флаг WGroupLeader обеспечивает такую возможность.

void HelpBrowser::updateCaption() { setCaption(tr("Help: %1").arg(textBrowser->documentTitle())); } Всякий раз, при переходе на другую страницу, вызывается слот updateCaption(). Функция documentTitle() возвращает текст, заданный в теге <title>. void HelpBrowser::showPage(const QString &page) { QString path = qApp->applicationDirPath() + "/doc"; HelpBrowser *browser = new HelpBrowser(path, page); browser->resize(500, 400); browser->show(); } В функции showPage() создается окно обозревателя и затем выводится на экран. Окно будет уничтожено автоматически, когда пользователь закроет его, поскольку в конструкторе был установлен флаг WDestructiveClose.

В данном примере мы исходим из предположения, что файлы справки находятся в подкаталоге doc.

Теперь можно вызвать обозреватель из приложения. Для этого, в главном окне приложения, мы создадим объект QAction -- Help и соединим его со слотом help():

void MainWindow::help() { HelpBrowser::showPage("index.html"); } Мы полагаем, что основной файл справки называется index.html. Чтобы вызвать обозреватель из диалога, нужно связать соответствующую кнопку Help со слотом help(): void EntryDialog::help() { HelpBrowser::showPage("dialogs.html#entrydialog"); } Здесь мы обращаемся уже к другому файлу справки -- dialogs.html и выполняем переход к ссылке entrydialog.

Еще одно место, откуда можно вызвать обозреватель справочной системы -- текст справки типа "What's This?". Для этого достаточно вставить в текст справки "What's This?" тег HTML <a href="...">.

Рисунок 16.4. Текст справки "What's This?" со ссылкой на файл справки.


Чтобы такая гипертекстовая ссылка работала, мы должны использовать класс, производный от QWhatsThis, который будет "знать", как вызвать обозреватель справочной системы. Для этого надо в классе-потомке перекрыть метод clicked(), в котором вызвать HelpBrowser:: showPage(). Ниже приводится определение класса: class MyWhatsThis : public QWhatsThis { public: MyWhatsThis(QWidget *widget, const QString &text); QString text(const QPoint &point); bool clicked(const QString &page); private: QString myText; }; Где text() и clicked() -- это методы предка, перекрываемые потомком. MyWhatsThis::MyWhatsThis(QWidget *widget, const QString &text) : QWhatsThis(widget) { myText = text; } Конструктор получает указатель на виджет и текст справки для этого виджета. Мы передаем указатель на виджет базовому конструктору и сохраняем текст справки в приватной переменной. QString MyWhatsThis::text(const QPoint &) { return myText; } Функция text() возвращает текст справки виджета, для заданных координат указателя мыши. Некоторые виджеты могут возвращать разный текст справки, в зависимости от того, где был произведен щелчок мышью, но в данном примере мы всегда будем возвращать один и тот же текст. bool MyWhatsThis::clicked(const QString &page) { if (page.isEmpty()) { return true; } else { HelpBrowser::showPage(page); return false; } } Функция clicked() вызывается в момент щелчка мышью по виджету, когда окно находится в режиме "What's This?". Если пользователь щелкает по гиперссылке, то функция получит название страницы в аргументе page. В противном случае в page будет пустая строка.

Возвращаемое значение используется базовым классом QWhatsThis для того, чтобы определить, что делать дальше -- скрыть (true) подсказку "What's This?" или оставить ее видимой (false). В данной ситуации мы хотим, чтобы текст "What's This?" оставался видимым на экране, поэтому возвращаем false. Когда пользователь щелкает по любому другому месту в тексте "What's This?", мы возвращаем true.

Ниже показан пример использования класса MyWhatsThis:

new MyWhatsThis(sourceLineEdit, tr("<img src=\"icon.png\">" "&nbsp;The meaning of the " "<a href=\"fields.html#source\">Source</a> field depends on " "the <a href=\"fields.html#type\">Type</a> field:" "<ul>" "<li><b>Books</b> have a Publisher</li>" "<li><b>Articles</b> have a Journal name with volume and " "issue number</li>" "<li><b>Thesis</b> have an Institution name and a department " "name</li>" "</ul>")); На этот раз, вместо вызова QWhatsThis::add(), мы создаем экземпляр класса MyWhatsThis для виджета, с текстом подсказки. Теперь пользователь может щелкнуть по гипертекстовой ссылке и вызвать обозреватель справочной системы.

Выглядит немного странно, так как мы создаем объект, но не связываем его с какой бы то ни было переменной. Но это только на первый взгляд, потому что Qt сама следит за создаваемыми объектами класса QWhatsThis и удаляет их, когда необходимость в них отпадает.