Рекомендованные практики для QML и Qt Quick
Несмотря на все преимущества QML и Qt Quick, они могут быть сложными в определенных ситуациях. В следующих разделах подробно описаны некоторые лучшие практики, которые помогут вам получить лучшие результаты при разработке приложений.
Настраиваемые элементы управления пользовательского интерфейса
Гибкий и современный пользовательский интерфейс является ключевым для успеха любого приложения в современном мире, и именно здесь QML так подходит для дизайнера или разработчика. Qt предлагает наиболее базовые элементы управления пользовательским интерфейсом, необходимые для создания гибкого и современного пользовательского интерфейса. Рекомендуется просмотреть этот список элементов управления пользовательским интерфейсом перед созданием собственного настраиваемого элемента управления пользовательским интерфейсом.
Помимо этих основных элементов управления пользовательским интерфейсом, предлагаемых самим Qt Quick, также доступен богатый набор элементов управления пользовательским интерфейсом Qt Quick Controls. Они удовлетворяют наиболее распространённым случаям использования без каких-либо изменений и предлагают гораздо больше возможностей с помощью настроек. В частности, Qt Quick Controls предоставляет параметры стилизации, которые соответствуют последним тенденциям дизайна пользовательского интерфейса. Если эти элементы управления пользовательским интерфейсом не удовлетворяют потребности вашего приложения, только тогда рекомендуется создать настраиваемый элемент управления.
Дополнительная информация
Стандарты кодирования
См. Стандарты кодирования QML.
Пакет ресурсов приложения
Большинство приложений зависят от ресурсов, таких как изображения и значки, для предоставления богатого пользовательского опыта. Часто бывает сложно обеспечить доступность этих ресурсов для приложения независимо от целевой ОС. Большинство популярных ОС применяют более строгие политики безопасности, ограничивающие доступ к файловой системе, что затрудняет загрузку этих ресурсов. В качестве альтернативы Qt предлагает собственную систему ресурсов, встроенную в двоичный файл приложения, обеспечивающую доступ к ресурсам приложения независимо от целевой ОС.
Например, рассмотрите следующую структуру каталогов проекта:
project
├── images
│ ├── image1.png
│ └── image2.png
├── project.pro
└── qml
└── main.qml Следующая запись в project.pro гарантирует, что ресурсы включены в двоичный файл приложения, делая их доступными при необходимости:
RESOURCES += \
qml/main.qml \
images/image1.png \
images/image2.png Более удобный подход заключается в использовании синтаксиса подстановочных знаков wildcard для выбора нескольких файлов одновременно:
RESOURCES += \
$$files(qml/*.qml) \
$$files(images/*.png) Этот подход удобен для приложений, которые зависят от ограниченного числа ресурсов. Однако всякий раз, когда новый файл добавляется в RESOURCES с помощью этого подхода, все остальные файлы в RESOURCES также перекомпилируются. Это может быть неэффективно, особенно для больших наборов файлов. В этом случае лучшим подходом является разделение каждого типа ресурсов в свой отдельный файл .qrc. Например, фрагмент кода выше можно изменить следующим образом:
qml.files = $$files(*.qml) qml.prefix = /qml RESOURCES += qml images.files = $$files(*.png) images.prefix = /images RESOURCES += images
Теперь, когда изменяется файл QML, перекомпилируются только файлы QML.
Иногда может потребоваться иметь больший контроль над путем для конкретного файла, управляемого системой ресурсов. Например, если мы хотели бы дать image2.png псевдоним, нам нужно будет переключиться на явный файл .qrc. Создание файлов ресурсов подробно объясняет, как это сделать.
Дополнительная информация
Разделение пользовательского интерфейса от логики
Одна из основных целей большинства разработчиков приложений – создание поддерживаемого приложения. Одним из способов достижения этой цели является разделение пользовательского интерфейса от бизнес-логики. Ниже приведены несколько причин, почему пользовательский интерфейс приложения должен быть написан на QML:
- Декларативные языки идеально подходят для определения пользовательских интерфейсов.
- Код QML проще писать, так как он менее подробен, чем C++, и не является строго типизированным. Это также делает его отличным языком для прототипирования, качество, которое имеет решающее значение при сотрудничестве с дизайнерами, например.
- JavaScript может легко использоваться в QML для реагирования на события.
В качестве строго типизированного языка C++ лучше всего подходит для логики приложения. Обычно такой код выполняет задачи, такие как сложные вычисления или обработка данных, которые выполняются быстрее на C++, чем на QML.
Qt предлагает различные подходы к интеграции кода QML и C++ в приложении. Типичный пример – отображение списка данных в пользовательском интерфейсе. Если набор данных статичный, простой и/или небольшой, модель, написанная на QML, может быть достаточной.
Следующий фрагмент демонстрирует примеры моделей, написанных на QML:
model: ListModel {
ListElement { name: "Item 1" }
ListElement { name: "Item 2" }
ListElement { name: "Item 3" }
}
model: [ "Item 1", "Item 2", "Item 3" ]
model: 10 Используйте C++ для динамических наборов данных, которые являются большими или часто изменяются.
Взаимодействие с QML из C++
Хотя Qt позволяет манипулировать QML из C++, это не рекомендуется. Чтобы объяснить почему, давайте рассмотрим упрощенный пример.
Получение ссылок из QML
Предположим, что мы пишем пользовательский интерфейс для страницы настроек:
import QtQuick 2.14
import QtQuick.Controls 2.14
Page {
Button {
text: qsTr("Restore default settings")
}
} Мы хотим, чтобы кнопка выполняла какое-то действие в C++ при нажатии. Мы знаем, что объекты в QML могут генерировать сигналы изменения, так же как и в C++, поэтому мы даем кнопке objectName, чтобы найти её из C++:
Button {
objectName: "restoreDefaultsButton"
text: qsTr("Restore default settings")
} Затем в C++ мы находим этот объект и подключаемся к его сигналу изменения:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSettings>
class Backend : public QObject
{
Q_OBJECT
public:
Backend() {}
public slots:
void restoreDefaults() {
settings.setValue("loadLastProject", QVariant(false));
}
private:
QSettings settings;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
Backend backend;
QObject *rootObject = engine.rootObjects().first();
QObject *restoreDefaultsButton = rootObject->findChild<QObject*>("restoreDefaultsButton");
QObject::connect(restoreDefaultsButton, SIGNAL(clicked()),
&backend, SLOT(restoreDefaults()));
return app.exec();
}
#include "main.moc" С этим подходом ссылки на объекты «извлекаются» из QML. Проблема с этим заключается в том, что слой логики C++ зависит от слоя представления QML. Если мы переработаем QML таким образом, что objectName изменится, или какое-то другое изменение нарушит возможность C++ найти объект QML, наш рабочий процесс станет намного сложнее и утомительнее.
Передача ссылок в QML
Переработка QML намного проще, чем переработка C++, поэтому для того, чтобы минимизировать трудности с обслуживанием, мы должны стремиться к тому, чтобы типы C++ были как можно менее осведомлены о QML. Этого можно достичь, «передав» ссылки на типы C++ в QML:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Backend backend;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("backend", &backend);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
} Затем QML вызывает слот C++ напрямую:
import QtQuick 2.14
import QtQuick.Controls 2.14
Page {
Button {
text: qsTr("Restore default settings")
onClicked: backend.restoreDefaults()
}
} С этим подходом C++ остаётся неизменным в случае, если QML необходимо переработать в будущем.
В примере выше мы установили свойство контекста в корневом контексте, чтобы экспонировать объект C++ в QML. Это означает, что свойство доступно для каждого компонента, загруженного движком. Свойства контекста полезны для объектов, которые должны быть доступны как можно скорее после загрузки QML и не могут быть созданы в QML.
Для быстрого руководства по выбору правильного подхода к экспонированию типов C++ в QML см. Выбор правильного метода интеграции между C++ и QML.
Дополнительная информация
Использование макетов Qt Quick
Qt предоставляет макеты Qt Quick для визуального расположения элементов Qt Quick в макете. В отличие от альтернативного варианта, позиционеров элементов, макеты Qt Quick также могут изменять размеры своих дочерних элементов при изменении размера окна. Хотя макеты Qt Quick часто являются предпочтительным выбором для большинства случаев использования, при их использовании необходимо учитывать следующие рекомендации:
Рекомендации
- Используйте anchors или свойства width и height для указания размера макета по отношению к его родительскому элементу, не являющемуся элементом макета.
- Используйте прикрепленное свойство Layout для установки атрибутов размера и выравнивания непосредственных дочерних элементов макета.
Не рекомендуется
- Не определяйте предпочтительные размеры для элементов, предоставляющих implicitWidth и implicitHeight, если их неявные размеры не соответствуют требованиям.
- Не используйте anchors для элемента, который является непосредственным дочерним элементом макета. Вместо этого используйте
Layout.preferredWidthиLayout.preferredHeight:RowLayout { id: layout anchors.fill: parent spacing: 6 Rectangle { color: 'azure' Layout.fillWidth: true Layout.minimumWidth: 50 Layout.preferredWidth: 100 Layout.maximumWidth: 300 Layout.minimumHeight: 150 Text { anchors.centerIn: parent text: parent.width + 'x' + parent.height } } Rectangle { color: 'plum' Layout.fillWidth: true Layout.minimumWidth: 100 Layout.preferredWidth: 200 Layout.preferredHeight: 100 Text { anchors.centerIn: parent text: parent.width + 'x' + parent.height } } }
Примечание: Макеты и anchors – это оба типа объектов, которые потребляют больше памяти и времени на создание экземпляров. Избегайте их использования (особенно в делегатах списков и таблиц, и стилях для элементов управления), когда простые связи со свойствами x, y, width и height достаточно.
Дополнительная информация
Безопасность типов
При объявлении свойств в QML легко и удобно использовать тип «var»:
property var name property var size property var optionsMenu
Однако этот подход имеет несколько недостатков:
- Если присвоено значение неправильного типа, сообщаемая ошибка укажет на местоположение объявления свойства, а не на местоположение, где свойство было присвоено. Это замедляет процесс разработки, затрудняя отслеживание ошибок.
- Статический анализ для обнаружения ошибок, упомянутых выше, невозможен.
- Фактический базовый тип свойства не всегда сразу понятен читателю.
Вместо этого всегда используйте фактический тип, когда это возможно:
property string name property int size property MyMenu optionsMenu
Производительность
Для получения информации о производительности в QML и Qt Quick см. Рекомендации по производительности и предложения.
Предпочитайте декларативные связи императивным присвоениям
В QML можно использовать императивный JavaScript-код для выполнения задач, таких как реагирование на события ввода, передача данных по сети и т. д. Императивный код играет важную роль в QML, но также важно знать, когда его не следует использовать.
Например, рассмотрим следующее императивное присвоение:
Rectangle {
Component.onCompleted: color = "red"
} Это имеет следующие недостатки:
- Это медленно. Свойство color сначала оценивается со значением по умолчанию, а затем снова с «красным» позже.
- Это откладывает ошибки, которые можно обнаружить на этапе сборки, до времени выполнения, что замедляет процесс разработки.
- Это перезаписывает любую декларативную связь, которая была установлена. В большинстве случаев это предполагается, но иногда это может быть непреднамеренным. См. Отладка перезаписи связей для получения дополнительной информации.
- Это мешает инструментарию; например, Qt Quick Designer не поддерживает JavaScript.
Код можно переписать, используя вместо этого декларативную связь:
Rectangle {
color: "red"
} Инструменты и утилиты
Для получения информации о полезных инструментах и утилитах, которые облегчают работу с QML и Qt Quick, см. Инструменты и утилиты Qt Quick.
Граф сцены
Для получения информации о графическом представлении сцен Qt Quick см. Графическое представление сцен Qt Quick.
Масштабируемые пользовательские интерфейсы
По мере улучшения разрешений дисплеев, масштабируемый пользовательский интерфейс приложения становится все более важным. Одним из подходов к достижению этого является сохранение нескольких копий пользовательского интерфейса для разных разрешений экрана и загрузка соответствующей копии в зависимости от доступного разрешения. Хотя это работает довольно хорошо, это увеличивает объем задач по техническому обслуживанию.
Qt предлагает лучшее решение этой проблемы и рекомендует разработчикам приложений следовать этим советам:
- Используйте якоря или модуль Qt Quick Layouts для размещения визуальных элементов.
- Не указывайте явную ширину и высоту для визуального элемента.
- Предоставляйте ресурсы пользовательского интерфейса, такие как изображения и значки, для каждого разрешения дисплея, поддерживаемого вашим приложением. Пример галереи Qt Quick Controls хорошо демонстрирует это, предоставляя
qt-logo.pngдля@2x,@3x, и@4xразрешений, что позволяет приложению работать с дисплеями высокого разрешения. Qt автоматически выбирает подходящее изображение для данного дисплея, при условии, что функция масштабирования высокой плотности пикселей явно включена. - Используйте изображения SVG для небольших значков. Хотя большие SVG могут быть медленными в отрисовке, маленькие работают хорошо. Векторные изображения исключают необходимость предоставления нескольких версий изображения, как это необходимо с растровыми изображениями.
- Используйте значки на основе шрифтов, такие как Font Awesome. Они масштабируются до любого разрешения дисплея, а также позволяют изменять цвет. Пример Qt Quick Controls Text Editor хорошо демонстрирует это.
При выполнении этих действий пользовательский интерфейс вашего приложения должен масштабироваться в зависимости от разрешения дисплея.
Связанная информация
- Пример галереи
- Пример текстового редактора
- Font Awesome
- Масштабируемость
- Дисплеи высокой плотности пикселей
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.14/qtquick-bestpractices.html