Глава 18. Платформо-зависимые особенности.

В этой главе будут рассмотрены некоторые из платформо-зависимых особенностей библиотеки Qt. Начнем с описания доступа к системному API: Win32 -- для Windows, Core Graphics -- для Mac OS X и Xlib -- для X11. Затем перейдем к рассмотрению расширения ActiveQt и покажем, как добавить поддержку ActiveX в свои приложения, для платформы Windows. В последнем разделе главы опишем, как можно добиться взаимодействия приложения с менеджером сессии на платформе X11.

Помимо расширений, представленных здесь, в состав версии Qt Enterprise Edition включено расширение Qt/Motif, которое облегчает миграцию приложений от Motif и Xt -- к Qt. Аналогичное расширение, для Tcl/Tk приложений предоставляет froglogic, и конвертер ресурсов Microsoft Windows -- Klaralvdalens Datakonsult. Для разработчиков устройств, Trolltech предоставляет среду исполнения приложений -- Qtopia. За дополнительной информацией обращайтесь по адресам:



18.1. Взаимодействие с API операционной системы.

Qt предоставляет достаточно мощный API, которого вполне достаточно для большинства приложений на любых платформах. Но в некоторых случаях невозможно обойтись без обращения к средствам, предоставляемым самой операционной системой. В этом разделе мы покажем, как можно организовать взаимодействие приложений с API операционной системы для выполнения специфических задач.

На всех, поддерживаемых библиотекой Qt, платформах, класс QWidget реализует функцию winId(), которая возвращает числовой идентификатор окна (HWND -- в терминах Windows). Коме того, QWidget предоставляет статическую функцию find(), которая возвращает QWidget по заданному идентификатору окна. Этот идентификатор может быть передан функциям API операционной системы для достижения эффектов, которые зависят от платформы. Например, следующий код использует winId(), чтобы добиться эффекта полупрозрачности, при отображении визуального компонента QLabel в Mac OS X, используя для этого функции графического ядра "Core Graphics". [1]

#include <qapplication.h> #include <qlabel.h> #include <qt_mac.h> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel *label = new QLabel("Hello Qt!", 0); app.setMainWidget(label); CGSWindowRef winRef = GetNativeWindowFromWindowRef((WindowRef)label->winId()); CGSSetWindowAlpha(_CGSDefaultConnection(), winRef, 0.5); label->show(); return app.exec(); } Следующий код добивается того же самого эффекта на платформе Windows, используя для этого Win32 API: #define _WIN32_WINNT 0x0501 #include <qapplication.h> #include <qt_windows.h> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel *label = new QLabel("Hello Qt!", 0); app.setMainWidget(label); int exstyle = GetWindowLong(label->winId(), GWL_EXSTYLE); exstyle |= WS_EX_LAYERED; SetWindowLong(label->winId(), GWL_EXSTYLE, exstyle); SetLayeredWindowAttributes(label->winId(), 0, 128, LWA_ALPHA); label->show(); return app.exec(); } Этот код будет корректно работать в среде Windows 2000/XP. Если вы желаете собрать и запустить приложение в более ранних версиях Windows, которые не поддерживают полупрозрачность, вам придется использовать библиотеку QLibrary, которая определяет функцию SetLayeredWindowAttributes во время исполнения, а не во время сборки: typedef BOOL (__stdcall *PSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD); PSetLayeredWindowAttributes pSetLayeredWindowAttributes = (PSetLayeredWindowAttributes) QLibrary::resolve("user32", "SetLayeredWindowAttributes"); if (pSetLayeredWindowAttributes) { int exstyle = GetWindowLong(label->winId(), GWL_EXSTYLE); exstyle |= WS_EX_LAYERED; SetWindowLong(label->winId(), GWL_EXSTYLE, exstyle); pSetLayeredWindowAttributes(label->winId(), 0, 128, LWA_ALPHA); } Qt/Windows использует такой подход, чтобы гарантировать возможность использования расширенных особенностей, таких как поддержка Unicode и преобразования шрифтов, везде, где это возможно, допуская при этом возможность работы приложений на старых версиях Windows.

В X11 нет стандартного способа добиться эффекта полупрозрачности. Однако, в этой среде у нас есть возможность изменить свойства окна:

Atom atom = XInternAtom(win->x11Display(), "MY_PROPERTY", False); long data = 1; XChangeProperty(win->x11Display(), win->winId(), atom, atom, 32, PropModeReplace, (unsigned char *)&data, 1); Qt/Embedded отличается от всех остальных версий Qt, где все это реализуется прямо поверх буфера изображений (frame buffer) Linux, без помощи промежуточного API. Она так же предоставляет свою собственную оконную систему -- QWS. За дополнительной информацией по Qt/Embedded обращайтесь по адресам: http://www.trolltech.com/products/embedded/ и http://doc.trolltech.com/3.2/winsystem.html.

При необходимости, можно использовать платформо-зависимые особенности не в ущерб переносимости, заключая специфический код в условные операторы препроцессора #if и #endif. Например:

#if defined(Q_WS_MAC) CGSWindowRef winRef = GetNativeWindowFromWindowRef((WindowRef)label->winId()); CGSSetWindowAlpha(_CGSDefaultConnection(), winRef, 0.5); #endif Для каждой из платформ, Qt определяет один из следующих символов: Q_WS_WIN, Q_WS_X11, Q_WS_MAC или Q_WS_QWS. Перед обращением к любому из них, исходный код приложения должен подключить хотя бы один заголовочный файл библиотеки. Кроме того, Qt предоставляет следующие символы препроцессора, для определения типа операционной системы:
  • Q_OS_WIN32

  • Q_OS_DGUX

  • Q_OS_LINUX

  • Q_OS_QNX6

  • Q_OS_WIN64

  • Q_OS_DYNIX

  • Q_OS_LYNX

  • Q_OS_RELIANT

  • Q_OS_CYGWIN

  • Q_OS_FREEBSD

  • Q_OS_NETBSD

  • Q_OS_SCO

  • Q_OS_MAC

  • Q_OS_HPUX

  • Q_OS_HPUX

  • Q_OS_SOLARIS

  • Q_OS_AIX

  • Q_OS_HURD

  • Q_OS_OSF

  • Q_OS_ULTRIX

  • Q_OS_BSDI

  • Q_OS_IRIX

  • Q_OS_QNX

  • Q_OS_UNIXWARE

Для большего удобства, Qt определяет символ Q_OS_WIN для Win32 и Win64, и Q_OS_UNIX для всех Unix-подобных систем, включая Mac OS X. Для уточнения номера версии операционной системы, во время исполнения, можно воспользоваться функциями QApplication::winVersion() (95, 98 и т.д.) и QApplication::macVersion() (10.0, 10.1 и т.д.).

Некоторые классы визуальных компонентов предоставляют платформозависимую функцию handle(). На рисунке 18.1 перечислены типы значений, возвращаемых функцией handle(), в зависимости от типа платформы.

Рисунок 18.1. Типы результата, возвращаемого функцией handle().




Некоторые классы, такие как QWidget, QPixmap, QPrinter и QPicture, ведут свою родословную от класса QPaintDevice. В X11 и Mac OS X, handle() означает то же самое самое, что и winId() класса QWidget. В Windows функция handle() возвращает контекст устройства, в то время как winId() -- дескриптор окна. Похожим образом, функция hbm(), класса QPixmap, в среде Windows, возвращает дескриптор растра (HBITMAP).

В X11, класс QPaintDevice предоставляет множество функций, которые возвращают различные указатели и дескрипторы, включая x11Display() и x11Screen(). Они могут использоваться для настройки графического контекста X11 в объектах QWidget или QPixmap.

Нередки ситуации, когда приложения, написанные с использованием библиотеки Qt, должны получить доступ к низкоуровневым событиям (XEvents -- в X11, MSG -- в Windows и Mac OS X, QWSEvents -- в Qt/Embedded) прежде, чем они будут преобразованы в QEvent. Добиться этого можно, породив свой класс от QApplication и перекрыв соответствующие фильтры событий: winEventFilter(), x11EventFilter(), macEventFilter() и qwsEventFilter().

Можно получить доступ к специфическим для платформы событиям, посылаемым заданному виджету, перекрыв одну из функций: winEvent(), x11Event(), macEvent() или qwsEvent(). Этот прием может оказаться единственно возможным, для обработки событий, которые обычно игнорируются библиотекой, например: событий от джойстика.

За дополнительной информацией, касающейся платформо-зависимых проблем, включая вопросы программирования с использованием Qt/Embedded и распространения готовых приложений для различных платформ, обращайтесь по адресу: http://doc.trolltech.com/3.2/winsystem.html.

Примечания

[1]

Возможно в Qt 3.3 будет включена возможность достигать этого эффекта независимо от типа операционной системы.