Spec-Zone.ru › Qt 6.1

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

Панель меню

Qt обнаруживает панели меню и преобразует их в родные панели меню Mac. Встраивание в существующие приложения 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.

Панель задач

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

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

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

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

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

Spec-Zone.ru

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