Жасмин Бланшет - QT 4: программирование GUI на С++
Вернемся к определению класса AddressBook. Третий вызов макроса Q_CLASSINFO() может показаться немного странным. По умолчанию элементы управления ActiveX предоставляют в распоряжение клиентов не только свои собственные свойства, сигналы и слоты, но и свои суперклассы вплоть до QWidget. Атрибут ToSuperClass позволяет определить суперкласс самого высокого уровня (в дереве наследования), который мы собираемся предоставить клиенту. Здесь мы указываем имя класса компонента («AddressBook») в качестве имени экспортируемого класса самого высокого уровня — это значит, что не будут экспортироваться свойства, сигналы и слоты, определенные в суперклассах AddressBook.
01 class ABItem : public QObject, public QListViewItem
02 {
03 Q_OBJECT
04 Q_PROPERTY(QString contact READ contact WRITE setContact)
05 Q_PROPERTY(QString address READ address WRITE setAddress)
06 Q_PROPERTY(QString phoneNumber
07 READ phoneNumber WRITE setPhoneNumber)
08 Q_CLASSINFO("ClassID",
09 "{bc82730e-5f39-4e5c-96be-461c2cd0d282}")
10 Q_CLASSINFO("InterfaceID",
11 "{c8bc1656-870e-48a9-9937-fbe1ceff8b2e}")
12 Q_CLASSINFO("ToSuperClass", "ABItem")
13 public:
14 ABItem(QTreeWidget *treeWidget);
15 void setContact(const QString &contact);
16 QString contact() const { return text(0); }
17 void setAddress(const QString &address);
18 QString address() const { return text(1); }
19 void setPhoneNumber(const QString &number);
20 QString phoneNumber() const { return text(2); }
21 public slots:
22 void remove();
23 };
Класс ABItem представляет один элемент в адресной книге. Он наследует QTreeWidgetItem и поэтому может отображаться в QTreeWidget, и он также наследует QObject и поэтому может экспортироваться как объект СОМ.
01 int main(int argc, char *argv[])
02 {
03 QApplication app(argc, argv);
04 if (!QAxFactory::isServer()) {
05 AddressBook addressBook;
06 addressBook.show();
07 return app.exec();
08 }
09 return app.exec();
10 }
В функции main() мы проверяем, в каком качестве работает приложение: как автономное приложение или как сервер. Опция командной строки —activex распознается объектом QApplication и обеспечивает работу приложения в качестве сервера. Если приложение не является сервером, мы создаем главный виджет и выводим его на экран, как мы обычно делаем для любого автономного приложения Qt.
Кроме опции —activex серверы ActiveX «понимают» следующие опции командной строки:
• —regserver — регистрация сервера в системном реестре;
• —unregserver — отмена регистрации сервера в системном реестре;
• —dumpidl файл — записывает описание сервера на языке IDL (Interface Description Language — язык описания интерфейсов) в указанный файл.
Когда приложение выполняет функции сервера, нам необходимо экспортировать классы AddressBook и ABItem как компоненты СОМ:
QAXFACTORY_BEGIN("{2b2b6f3e-86cf-4c49-9df5-80483b47f17b}",
"{8e827b25-148b-4307-ba7d-23f275244818}")
QAXCLASS(AddressBook)
QAXTYPE(ABItem)
QAXFACTORY_END()
Приведенные выше макросы экспортируют фабрику классов для создания объектов СОМ. Поскольку мы собираемся экспортировать два типа объектов СОМ, мы не можем просто использовать макрос QAXFACTORY_DEFAULT(), как мы делали в предыдущем примере.
Первым аргументом макроса QAXFACTORY_BEGIN() является идентификатор библиотеки типов; второй аргумент представляет собой идентификатор приложения. Между макросами QAXFACTORY_BEGIN() и QAXFACTORY_END() мы указываем все классы, которые могут быть инстанцированы, и все типы данных, доступные как объекты СОМ.
Ниже приводится файл .pro для внепроцессного сервера ActiveX:
TEMPLATE = app
CONFIG += qaxserver
HEADERS = abitem.h
addressbook.h
editdialog.h
SOURCES = abitem.cpp
addressbook.cpp
editdialog.cpp
main.cpp
FORMS = editdialog.ui
RC_FILE = qaxserver.rc
Файл qaxserver.rc, на который имеется ссылка в файле .pro, является стандартным файлом, который может быть скопирован из каталога Qt srcactiveqtcontrol.
Вы можете посмотреть в каталоге примеров vb проект Visual Basic, который использует сервер Address Book.
Этим мы завершаем наш обзор рабочей среды ActiveQt. Дистрибутив Qt включает дополнительные примеры, и в документации содержится информация о способах построения модулей QAxContainer и QAxServer и решения обычных вопросов взаимодействия.
Управление сеансами в системе X11
Когда мы выходим из системы X11, некоторые оконные менеджеры спрашивают нас о необходимости сохранения сеанса. Если мы отвечаем утвердительно, то при следующем входе в систему работа приложений будет автоматически возобновлена с того же экрана и, в идеальном случае, с того же состояния, которое было во время выхода из системы.
Компонент системы X11, который обеспечивает сохранение и восстановление сеанса, называется менеджером сеансов (session manager). Для того чтобы приложение Qt/X11 «осознавало» присутствие менеджера сеансов, мы должны переопределить функцию QApplication::saveState() и сохранить там состояние приложения.
Рис. 20.7. Выход из системы KDE.
Windows 2000 и XP, а также некоторые системы Unix предлагают другой механизм, который носит название «спящих процессов» (hibernation). Когда пользователь останавливает компьютер, операционная система просто выгружает оперативную память компьютера на диск и загружает ее обратно, когда компьютер «просыпается». Приложениям ничего не надо делать, и они даже могут ничего не знать об этом.
Когда пользователь инициирует завершение работы, мы можем перехватить управление непосредственно перед завершением путем переопределения функции QApplication::commitData(). Это позволяет нам сохранять измененные данные и при необходимости вступать в диалог с пользователем. Эта часть схемы управления сеансом поддерживается как в системе X11, так и в Windows.
Мы рассмотрим управление сеансом через программный код приложения Tic-Tac-Toe (крестики-нолики), которое работает под управлением менеджера сеансов. Во-первых, давайте рассмотрим функцию main():
01 int main(int argc, char *argv[])
02 {
03 Application app(argc, argv);
04 TicTacToe toe;
05 toe.setObjectName("toe");
06 app.setTicTacToe(&toe);
07 toe.show();
08 return app.exec();
09 }
Мы создаем объект Application. Класс Application наследует QApplication и переопределяет две функции commitData() и saveState() для обеспечения управления сеансом.
Затем мы создаем виджет TicTacToe, даем знать об этом объекту Application и отображаем его. Мы дали виджету TicTacToe имя «toe». Мы должны давать уникальные имена виджетам верхнего уровня, если мы хотим, чтобы менеджер сеансов мог восстановить размеры и позиции окон.
Рис. 20.8. Приложение Tic-Tac-Toe.
Ниже приводится определение класса Application:
01 class Application : public QApplication
02 {
03 Q_OBJECT
04 public:
05 Application(int &argc, char *argv[]);
06 void setTicTacToe(TicTacToe *tic);
07 void saveState(QSessionManager &sessionManager);
08 void commitData(QSessionManager &sessionManager);
09 private:
10 TicTacToe *ticTacToe;
11 };
Класс Application сохраняет указатель виджета TicTacToe в закрытой переменной.
01 void Application::saveState(QSessionManager &sessionManager)
02 {
03 QString fileName = ticTacToe->saveState();
04 QStringList discardCommand;
05 discardCommand << "rm" << fileName;
06 sessionManager.setDiscardCommand(discardCommand);
07 }
В системе X11 функция saveState() вызывается, когда менеджер сеансов собирается сохранить состояние приложения. Данная функция также имеется на других платформах, но никогда не вызывается. Параметр QSessionManager позволяет нам поддерживать связь с менеджером сеансов.
Мы начинаем с попытки сохранения виджетом TicTacToe своего состояния в некоторый файл. Затем мы задаем команду для выполнения сброса состояния менеджером сеансов. Команда сброса (discard command) — это команда, которую должен выполнять менеджер сеансов для удаления любой сохраненной ранее информации, связанной с текущим состоянием. В этом примере мы задаем ее в виде
rm файл_сеанса
где файл_сеанса — имя файла, который содержит сохраненное состояние сеанса, a rm — стандартная команда удаления файлов в системе Unix.