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_PluginApplication
- Qt::AA_DontUseNativeMenuBar
- Qt::AA_MacDontSwapCtrlAndMeta
- Qt::WA_MacOpaqueSizeGrip
- Qt::WA_MacShowFocusRect
- Qt::WA_MacNormalSize
- Qt::WA_MacSmallSize
- Qt::WA_MacMiniSize
- Qt::WA_MacVariableSize
- Qt::WA_MacAlwaysShowToolWindow
- 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() и применяя следующие тесты:
- Если окно содержит QMenuBar, то оно используется.
- Если окно модальное, то используется его панель меню. Если панель меню не указана, используется стандартная панель меню (как описано ниже).
- Если окно не имеет родителя, используется стандартная панель меню (как описано ниже).
Эти тесты выполняются по всей цепочке родительских окон до тех пор, пока не будет удовлетворено одно из вышеуказанных правил. Если все остальные варианты не подходят, будет создана стандартная панель меню. Стандартная панель меню в 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, как Frameworks и пакеты. Важно учитывать эти структуры, так как они напрямую влияют на развертывание приложений.
Qt предоставляет инструмент развертывания macdeployqt для упрощения процесса развертывания. Статья Qt для macOS — Развертывание более подробно описывает процесс развертывания.
Библиотеки Qt как Frameworks
По умолчанию Qt компилируется как набор Frameworks. Frameworks — это предпочтительный способ распространения библиотек в macOS. Сайт Руководства по программированию с использованием Frameworks Apple содержит гораздо больше информации о Frameworks.
Важно помнить, что Frameworks всегда связываются с релизными версиями библиотек. Если требуется отладочная версия Qt Framework, используйте переменные окружения DYLD_IMAGE_SUFFIX, чтобы убедиться в загрузке отладочной версии:
export DYLD_IMAGE_SUFFIX=_debug
В качестве альтернативы можно временно поменять отладочную и релизную версии, что описано в технической заметке Apple "Отладка магии".
Если вы не хотите использовать Frameworks, просто настройте 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 и аналогичных стандартных расположений.
Комбинирование библиотек
Если вы хотите создать новую динамическую библиотеку, объединив динамические библиотеки Qt, вам необходимо использовать флаг 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 и QOperatingSystemVerison содержит информацию о проверке версии во время выполнения.
Доступ к родным 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.
Руководство по программированию пакетов содержит информацию о пакетах и локализованном ресурсном каталоге.
Использование нативных панелей 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. Она не влияет на плагины или статические сборки.
QtDBus и 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 поддерживает диалоговые окна (sheets), представленные флагом окна 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-6.2/macos-issues.html