Spec-Zone.ru › Qt 5.15

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

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

Aqua

Стиль Aqua является неотъемлемой частью платформы macOS. Как и Cocoa, Qt предоставляет виджеты, которые выглядят так же, как описано в Руководстве по разработке пользовательского интерфейса macOS. Обратите внимание, что, хотя виджеты Qt используют AppKit для внешнего вида и ощущений, каждый отдельный виджет Qt не представлен как обернутый родной элемент управления.

На странице Галерея виджетов 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. Это сопоставится с событием контекстного меню, например, с меню, которое отобразит всплывающее меню выбора. Это наиболее распространенное использование правого щелчка мыши и сопоставляется с щелчком правой кнопкой мыши с поддержкой однокнопочной мыши macOS.

Панель меню

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

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

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

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

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

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

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

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

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

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

Панель задач

Взаимодействие с панелью задач возможно. Иконка может быть установлена вызовом 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 «Debugging Magic».

Если вы не хотите использовать фреймворки, просто настройте 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();
}

Ограничения

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 создаёт нативный пункт меню Выход, который реагирует на сочетание клавиш CMD+Q. Создание QAction для роли QAction::QuitRole заменит этот пункт меню. Поэтому действие замены должно быть подключено к слоту QCoreApplication::quit или к пользовательскому слоту, который завершает работу приложения.

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

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

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

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

Spec-Zone.ru

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