Spec-Zone.ru › Qt 5.9

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();
}

Ограничения

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/qt-5.9/osx-issues.html

Spec-Zone.ru

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