Spec-Zone.ru › Qt 5.12

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.

Панель инструментов

Взаимодействие с панелью инструментов возможно. Иконка может быть установлена с помощью вызова 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();
}

Ограничения

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 приложении, нативный означает приложение, которое взаимодействует непосредственно с базовой системой окон, а не через какой-либо промежуточный слой. Приложения Qt работают как полноправные граждане, как и приложения Cocoa и Carbon. Мы используем Cocoa для внутреннего взаимодействия с операционной системой.

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

Spec-Zone.ru

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