Spec-Zone.ru › Qt 5.11

Qt для macOS — Особенности

На этой странице описаны основные проблемы, связанные с поддержкой macOS в Qt. Терминология macOS и специфические процессы можно найти на сайте https://developer.apple.com/.

Aqua

Aqua — неотъемлемая часть платформы macOS. Как и в случае с Cocoa и Carbon, Qt предоставляет виджеты, которые соответствуют описаниям в руководствах по пользовательскому интерфейсу. Виджеты Qt используют HIThemes для реализации внешнего вида. Другими словами, мы используем собственные API Apple для рендеринга. Более подробная документация по Aqua находится на странице Руководства по пользовательскому интерфейсу macOS.

На странице Галерея виджетов Qt содержатся примерные изображения приложений, использующих тему macOS.

Атрибуты Qt для macOS

Ниже приведены полезные атрибуты, которые можно использовать для настройки приложений на macOS:

  • Qt::AA_MacPluginApplication
  • Qt::AA_DontUseNativeMenuBar
  • Qt::AA_MacDontSwapCtrlAndMeta
  • Qt::WA_MacNoClickThrough
  • Qt::WA_MacOpaqueSizeGrip
  • Qt::WA_MacShowFocusRect
  • Qt::WA_MacNormalSize
  • Qt::WA_MacSmallSize
  • Qt::WA_MacMiniSize
  • Qt::WA_MacVariableSize
  • Qt::WA_MacBrushedMetal
  • Qt::WA_MacAlwaysShowToolWindow
  • Qt::WA_MacFrameworkScaled
  • Qt::WA_MacNoShadow
  • Qt::Sheet
  • Qt::Drawer
  • Qt::MacWindowToolBarButtonHint,
  • QMainWindow::unifiedTitleAndToolBarOnMac

macOS всегда выполняет двойную буферизацию экрана, поэтому атрибут Qt::WA_PaintOnScreen не имеет эффекта. Также невозможно рисовать за пределами события рисования, поэтому Qt::WA_PaintOutsidePaintEvent тоже не имеет эффекта.

Правый щелчок мыши

Класс QContextMenuEvent обеспечивает поддержку правого щелчка мыши для приложений macOS. Это будет соответствовать событию контекстного меню, например, меню, которое отобразит всплывающее меню выбора. Это наиболее распространённое использование правого щелчка, и оно соответствует нажатию клавиши Control с помощью поддержки мыши macOS с одной кнопкой.

Панель меню

Qt обнаруживает панели меню и преобразует их в родные панели меню macOS. Интеграция в существующие приложения Qt обычно происходит автоматически. Однако, если у вас есть особые потребности, текущая реализация Qt выбирает панель меню, начиная с активного окна (например, QGuiApplication::focusWindow()) и применяет следующие проверки:

  1. Если у окна есть QMenuBar, то оно используется.
  2. Если окно является модальным, то используется его панель меню. Если панель меню не указана, используется стандартная панель меню (как описано ниже).
  3. Если у окна нет родительского окна, используется стандартная панель меню (как описано ниже).

Эти проверки выполняются по всей цепочке родительских окон до тех пор, пока не будет выполнено одно из вышеперечисленных правил. Если ничего не подходит, будет создана стандартная панель меню. Стандартная панель меню в Qt — это пустая панель меню. Однако вы можете создать другую стандартную панель меню, создав QMenuBar без родительского окна. Первое созданное окно будет назначено стандартной панелью меню и будет использоваться всякий раз, когда требуется стандартная панель меню.

Использование родных панелей меню вносит определённые ограничения на классы Qt. Более подробная информация приведена в разделе с списком ограничений ниже.

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

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

Каждый QAction имеет свойство menuRole, которое контролирует специальное расположение элементов меню приложения; однако по умолчанию menuRole равен TextHeuristicRole, что означает, что элементы меню будут автоматически определяться по их тексту.

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

Специальные клавиши

Для обеспечения ожидаемого поведения приложений Qt на macOS значения перечисления Qt::Key_Meta, Qt::MetaModifier и Qt::META соответствуют клавишам Control на стандартной клавиатуре Apple, а значения Qt::Key_Control, Qt::ControlModifier и Qt::CTRL соответствуют клавишам Command.

Панель задач (Dock)

Взаимодействие с панелью задач возможно. Иконку можно установить, вызвав QWindow::setWindowIcon() из главного окна вашего приложения. Вызов setWindowIcon() можно делать столько раз, сколько необходимо, обеспечивая легко обновляемую иконку.

Доступность

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

Поддержка библиотек и развертывания

Qt поддерживает структуры macOS, такие как фреймворки и пакеты. Важно понимать эти структуры, поскольку они напрямую влияют на развертывание приложений.

Qt предоставляет инструмент развертывания macdeployqt, чтобы упростить процесс развертывания. Статья Qt для macOS — Развертывание более подробно описывает процесс развертывания.

Библиотеки Qt в качестве фреймворков

По умолчанию Qt собирается как набор фреймворков. Фреймворки — это предпочтительный способ распространения библиотек в macOS. На сайте Руководство Apple по программированию фреймворков содержится гораздо больше информации о фреймворках.

Важно помнить, что фреймворки всегда связываются с релизными версиями библиотек. Если требуется отладочная версия фреймворка Qt, используйте DYLD_IMAGE_SUFFIX переменные окружения, чтобы убедиться, что загружена отладочная версия:

export DYLD_IMAGE_SUFFIX=_debug

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

Если вы не хотите использовать фреймворки, просто настройте Qt с -no-framework.

./configure -no-framework

Библиотеки на основе пакетов

Если вы хотите использовать некоторые динамические библиотеки в пакете приложения macOS (каталог приложения), создайте подкаталог с именем Frameworks в каталоге пакета приложения и поместите туда свои динамические библиотеки. Приложение найдёт динамическую библиотеку, если у неё есть имя установки @executable_path/../Frameworks/libname.dylib.

Если вы используете qmake и Makefiles, используйте настройку QMAKE_LFLAGS_SONAME:

QMAKE_LFLAGS_SONAME  = -Wl,-install_name,@executable_path/../Frameworks/

В качестве альтернативы можно изменить имя установки с помощью install_name_tool(1) в командной строке.

Переменная окружения DYLD_LIBRARY_PATH переопределит эти настройки и любые другие стандартные пути, такие как поиск динамических библиотек внутри /usr/lib и аналогичных стандартных расположений.

Если вы используете старые версии GDB, вам необходимо использовать полный путь к исполняемому файлу. Более поздние версии позволяют передавать имя пакета в командной строке.

Объединение библиотек

Если вы хотите создать новую динамическую библиотеку, объединив динамические библиотеки Qt 4, вам нужно включить ld -r флаг. Тогда информация о перебазировании будет храниться в выходном файле, так что этот файл можно будет использовать в другом ld запуске. Это делается путём установки -r флага в файле .pro, и LFLAGS настроек.

Порядок инициализации

dyld(1) вызывает глобальные статические инициализаторы в порядке их связывания в приложение. Если библиотека подключается к Qt и ссылается на глобальные переменные в Qt (из глобальных инициализаторов в вашей собственной библиотеке), свяжите приложение с Qt перед связыванием его с библиотекой. В противном случае результат будет неопределённым, поскольку глобальные инициализаторы Qt ещё не вызваны.

Флаги времени компиляции

Следующие флаги полезны, когда вы хотите определить код, специфичный для macOS:

  • Q_OS_DARWIN определён, когда Qt обнаруживает, что вы находитесь на Darwin-системе, такой как macOS или iOS.
  • Q_OS_MACOS определён, когда вы находитесь на системе macOS.

Примечание: Q_WS_MAC больше не определён в Qt 5.

Если вы хотите определить код для определённых версий macOS, используйте макросы доступности, определённые в файле /usr/include/AvailabilityMacros.h.

Документация QSysInfo содержит информацию о проверке версии во время выполнения.

Доступ к родным API macOS

Получение пути к пакету приложения

Приложения macOS структурированы как каталог (заканчивающийся на .app). Этот каталог содержит подкаталоги и файлы. Может быть полезно размещать элементы, такие как плагины и онлайн-документация, внутри этого пакета. Следующий код возвращает путь к пакету приложения:

#ifdef Q_OS_MAC
    CFURLRef appUrlRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
    CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef,
                                           kCFURLPOSIXPathStyle);
    const char *pathPtr = CFStringGetCStringPtr(macPath,
                                           CFStringGetSystemEncoding());
    qDebug("Path = %s", pathPtr);
    CFRelease(appUrlRef);
    CFRelease(macPath);
#endif

Примечание: Когда macOS настроен на использование японского языка, в этом коде возникает ошибка, и он возвращает пустую строку. Поэтому всегда проверяйте возвращаемую строку.

Для получения дополнительной информации об использовании API CFBundle посетите веб-сайт разработчиков Apple .

QCoreApplication::applicationDirPath() можно использовать для определения пути к исполняемому файлу внутри пакета.

Перевод меню приложения и родных диалоговых окон

Элементы в меню приложения будут корректно объединены для локализованных приложений, но они не отобразятся переведёнными, пока в пакет приложения не будет добавлен папка с локализованными ресурсами. к пакету приложения.

По сути, необходим файл с именем locversion.plist. Вот пример приложения с норвежской локализацией:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>LprojCompatibleVersion</key>
    <string>123</string>
    <key>LprojLocale</key>
    <string>no</string>
    <key>LprojRevisionLevel</key>
    <string>1</string>
    <key>LprojVersion</key>
    <string>123</string>
</dict>
</plist>

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

Руководство по программированию пакетов содержит информацию о пакетах и папке с локализованными ресурсами.

Смешение Qt с кодом нативными

Для добавления нативных виджетов и элементов управления Cocoa внутри приложения Qt или для встраивания Qt в нативное приложение Cocoa доступны два класса: QMacCocoaViewContainer и QMacNativeWidget.

Использование нативных панелей Cocoa

Диспечер событий Qt более гибкий, чем в Cocoa, и позволяет пользователю запускать диспечер событий (и выполнение QEventLoop::exec) без необходимости думать о том, отображаются ли модальные диалоговые окна на экране (что отличается от Cocoa). Поэтому нам нужно выполнить дополнительное управление в Qt, чтобы обработать это правильно, что, к сожалению, затрудняет смешивание нативных панелей. В настоящее время лучший способ сделать это — следовать приведенной ниже схеме, где мы публикуем вызов функции нативным кодом, а не вызываем его напрямую. Тогда мы знаем, что Qt корректно обновил все ожидающие рекурсии цикла событий до отображения нативной панели:

#include <QtGui>

class NativeProxyObject : public QObject
{
    Q_OBJECT
public slots:
    void execNativeDialogLater()
    {
        QMetaObject::invokeMethod(this, "execNativeDialogNow", Qt::QueuedConnection);
    }

    void execNativeDialogNow()
    {
        NSRunAlertPanel(@"A Native dialog", @"", @"OK", @"", @"");
    }

};

#include "main.moc"

int main(int argc, char **argv){
    QApplication app(argc, argv);
    NativeProxyObject proxy;
    QPushButton button("Show native dialog");
    QObject::connect(&button, SIGNAL(clicked()), &proxy, SLOT(execNativeDialogLater()));
    button.show();
    return app.exec();
}

Ограничения

Fink

Если вы установили пакет Qt для X11 из Fink, он установит переменную среды QMAKESPEC в значение darwin-g++. Это вызовет проблемы при сборке пакета Qt для macOS. Чтобы исправить это, просто снимите значение вашей переменной QMAKESPEC или установите её значение на macx-g++ перед запуском configure. Чтобы получить новую дистрибуцию Qt, выполните make confclean в командной строке.

MySQL и macOS

Похоже, что проблема возникает, когда -prebind и -multi_module определены при линковании статических C-библиотек в динамические библиотеки. Если при линковке Qt вы получите следующее сообщение об ошибке:

ld: common symbols not allowed with MH_DYLIB output format with the -multi_module option
/usr/local/mysql/lib/libmysqlclient.a(my_error.o) definition of common _errbuff (size 512)
/usr/bin/libtool: internal link edit command failed

перелинкуйте Qt, используя -single_module. Эта проблема возникает только при компиляции драйвера MySQL в Qt. Она не влияет на плагины или статические сборки.

D-Bus и macOS

Модуль QtDBus по умолчанию динамически загружает библиотеку libdbus-1 на macOS. Это означает, что приложения, ссылающиеся на модуль QtDBus, будут загружаться даже на системах macOS, на которых нет библиотек, но они не смогут подключиться к любому серверу D-Bus и не смогут открыть сервер с помощью QDBusServer.

Для использования функциональности D-Bus необходимо установить библиотеку libdbus-1, например, через Homebrew, Fink или MacPorts. Вы можете включить эти библиотеки в пакет приложения, если вы развертываете его на других системах. Кроме того, обратите внимание, что на macOS нет системного шины, и шина сеансов будет запущена только после того, как launchd будет настроен для её управления.

Действия в меню

  • Действия в QMenu с ускорителями, имеющими более одного нажатия клавиш (QKeySequence), не будут отображаться корректно, когда QMenu переводится в нативную строку меню Mac. Будет отображена только первая клавиша. Однако сочетание клавиш по-прежнему будет активироваться, как на всех других платформах.
  • Объекты QMenu, используемые в нативной строке меню, не могут обрабатывать события Qt через обычные обработчики событий. Установите делегата на меню для уведомления о таких изменениях. В качестве альтернативы, рассмотрите использование сигналов QMenu::aboutToShow() и QMenu::aboutToHide() для отслеживания видимости меню; это обеспечивает решение, которое должно работать на всех платформах, поддерживаемых Qt.

Нативные виджеты

Qt поддерживает диалоговые окна, представленные флагом окна Qt::Sheet.

Обычно, когда речь идёт о нативном приложении macOS, нативное означает приложение, которое взаимодействует напрямую с базовой системной оболочкой, а не приложение, использующее какой-либо промежуточный слой. Приложения Qt работают как полноправные пользователи, точно так же, как приложения Cocoa и Carbon. Внутренне мы используем Cocoa для взаимодействия с операционной системой.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/archives/qt-5.11/osx-issues.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API