Применение «родных» программных интерфейсов

Применение «родных» программных интерфейсов

Всесторонний программный интерфейс Qt удовлетворяет большинству требований на всех платформах, но при некоторых обстоятельствах нам может потребоваться базовый, платформозависимый программный интерфейс. В данном разделе мы продемонстрируем способы применения «родных» программных интерфейсов различных платформ, поддерживаемых Qt, для решения конкретных задач.

Для каждой платформы класс QWidget поддерживает функцию winId(), которая возвращает идентификатор или описатель окна. QWidget также обеспечивает статическую функцию find(), которая возвращает QWidget с идентификатором конкретного окна. Мы можем передавать этот идентификатор функциям «родного» программного интерфейса для достижения эффектов, зависимых от платформы. Например, в следующем программном коде используется функция winId() для отображения слева заголовка панели инструментов, используя «родные» функции Mac OS X:

#ifdef Q_WS_MAC

ChangeWindowAttributes(HIViewGetWindow(HIViewRef(toolWin.winId())),

kWindowSideTitlebarAttribute, kWindowNoAttributes);

#endif

Рис. 20.1. Окно панели инструментов Mac OS X с отображением заголовка сбоку.

Ниже показано, как в системе X11 мы можем модифицировать свойство окна:

#ifdef Q_WS_X11

Atom atom = XInternAtom(QX11Info::display(), "MY_PROPERTY", False);

long data = 1;

XChangeProperty(QX11Info::display(), window->winId(), atom, atom,

32, PropModeReplace, reinterpret_cast<uchar *>(&data), 1);

#endif

Использование директив #ifdef и #endif вокруг зависимого от платформы программного кода гарантирует компиляцию приложения на других платформах.

Приведенный ниже пример показывает, как в приложениях, предназначенных только для Windows, можно использовать вызовы GDI для рисования на виджете Qt:

01 void GdiControl::paintEvent(QPaintEvent * /* event */)

02 {

03 RECT rect;

04 GetClientRect(winId(), &rect);

05 HDC hdc = GetDC(winId());

06 FillRect(hdc, &rect, HBRUSH(COLOR_WINDOW + 1));

07 SetTextAlign(hdc, TA_CENTER | TA_BASELINE);

08 TextOutW(hdc, width() / 2, height() / 2,

09 text.utf16(), text.size());

10 ReleaseDC(winId(), hdc);

11 }

Чтобы это сработало, мы должны также переопределить функцию QPaintDevice::paintEngine() для возврата нулевого указателя и установить атрибут Qt::WA_PaintOnScreen в конструкторе виджета.

Следующий пример показывает, как можно сочетать QPainter и GDI в обработчике события рисования, используя функции getDC() и releaseDC() класса QPaintEngine:

01 void MyWidget::paintEvent(QPaintEvent * /* event */)

02 {

03 QPainter painter(this);

04 painter.fillRect(rect().adjusted(20, 20, -20, -20), Qt::red);

05 #ifdef Q_WS_WIN

06 HDC hdc = painter.paintEngine()->getDC();

07 Rectangle(hdc, 40, 40, width() - 40, height() - 40);

08 painter.paintEngine()->releaseDC();

09 #endif

10 }

Подобное совмещение вызовов QPainter и GDI иногда может дать странный результат, особенно когда вызовы QPainter выполняются после вызовов GDI, потому что QPainter делает некоторые предположения о состоянии базового уровня рисования.

Qt определяет один из следующих четырех символов оконной системы: Q_WS_WIN, Q_WS_X11, Q_WS_MAC и Q_WS_QWS (Qtopia). Мы должны обеспечить включение хотя бы одного заголовка Qt перед их использованием в приложениях. Qt также обеспечивает препроцессорные символы для идентификации операционной системы:

• Q_OS_AIX

• Q_OS_BSD4

• Q_OS_BSDI

• Q_OS_CYGWIN

• Q_OS_DGUX

• Q_OS_DYNIX

• Q_OS_FREEBSD

• Q_OS_HPUX

• Q_OS_HURD

• Q_OS_IRIX

• Q_OS_LINUX

• Q_OS_LYNX

• Q_OS_MAC

• Q_OS_NETBSD

• Q_OS_OPENBSD

• Q_OS_OS2EMX

• Q_OS_OSF

• Q_OS_QNX6

• Q_OS_QNX

• Q_OS_RELIANT

• Q_OS_SCO

• Q_OS_SOLARIS

• Q_OS_ULTRIX

• Q_OS_UNIXWARE

• Q_OS_WIN32

• Q_OS_WIN64

Мы можем считать, что по крайней мере один из этих символов будет определен. Для удобства Qt также определяет Q_OS_WIN, когда обнаруживается Win32 или Win64, и Q_OS_UNIX, когда обнаруживается любая операционная система типа Unix (включая Linux и Mac OS X). Во время выполнения приложений мы можем проверить QSysInfo::WindowsVersion или QSysInfo::MacintoshVersion для установки отличий между различными версиями Windows (2000, ME и так далее) или Mac OS X (10.2, 10.3 и так далее).

Кроме макросов операционной и оконной систем существует также ряд макросов компилятора. Например, Q_CC_MSVC определяется в том случае, если компилятором является Visual С++ компании Microsoft. Такие макросы полезны, когда приходится обходить ошибки компилятора.

Несколько классов графического пользовательского интерфейса Qt обеспечивают зависимые от платформы функции, которые возвращают описатели (handle) базового объекта для низкоуровневой обработки. Они перечислены на рис. 20.2:

Mас OS X:

• ATSFontFormatRef QFont::handle();

• CGImageRef QPixmap::macCGHandle();

• GWorldPtr QPixmap::macQDAlphaHandle();

• GWorldPtr QPixmap::macQDHandle();

• RgnHandle QRegion::handle();

• HIViewRef QWidget::winId();

Windows:

• HCURSOR QCursor::handle();

• HDC QPaintEngine::getDC();

• HDC QPrintEngine::getPrinterDC();

• HFONT QFont::handle();

• HPALETTE QColormap::hPal();

• HRGN QRegion::handle();

• HWND QWidget::winId();

X11:

• Cursor QCursor::handle();

• Font QFont::handle();

• Picture QPixmap::x11PictureHandle();

• Picture QWidget::x11PictureHandle();

• Pixmap QPixmap::handle();

• QX11Info QPixmap::x11Info();

• QX11Info QWidget::x11Info();

• Region QRegion::handle();

• Screen QCursor::x11Screen();

• SmcConn QSessionManager::handle();

• Window QWidget::handle();

• Window QWidget::winId();

В системе X11 функции QPixmap::x11Info() и QWidget::x11Info() возвращают объект QX11Info, который обеспечивает различные указатели и описатели с помощью ряда функций, включая display(), screen(), colormap() и visual(). Мы можем использовать их для настройки графического контекста, например QWidget или QPixmap.

Приложениям Qt, которым необходимо взаимодействовать с другими инструментальными средствами и библиотеками, часто приходится осуществлять доступ к низкоуровневым событиям (XEvent в системе X11, MSG в системе Windows, Eventref в системе Mac OS X, QWSEvent для Qtopia), прежде чем они будут преобразованы в события QEvent. Мы можем делать это путем создания подкласса QApplication и переопределения соответствующего зависимого от платформы фильтра событий — одну из следующих функций: x11EventFilter(), winEventFilter(), macEventFilter() и qwsEventFilter(). Мы можем поступать по-другому и осуществлять доступ к зависимым от платформы событиям, которые передаются заданному QWidget путем переопределения какой-то одной из функций winEvent(), x11Event(), macEvent() и qwsEvent(). Это может пригодиться для обработки событий определенного типа, которые Qt обычно игнорирует, например события джойстика.

Более подробную информацию относительно применения зависимых от платформы средств, в том числе как развертывать приложения Qt на различных платформах, можно найти в сети Интернет по адресу http://doc.trolltech.com/4.1/win-system.html.