Spec-Zone.ru › Qt 6.1

Рекомендованные Практики для QML и Qt Quick

Несмотря на все преимущества, которые предлагают QML и Qt Quick, они могут быть сложными в определенных ситуациях. В следующих разделах подробно описаны лучшие практики, которые помогут вам получить лучшие результаты при разработке приложений.

Настраиваемые элементы управления пользовательского интерфейса

Гибкий и современный пользовательский интерфейс является ключевым для успеха любого приложения в современном мире, и именно здесь QML так хорошо подходит для дизайнера или разработчика. Qt предоставляет самые основные элементы управления пользовательским интерфейсом, необходимые для создания гибкого и современного пользовательского интерфейса. Рекомендуется ознакомиться с этим списком элементов управления пользовательским интерфейсом перед созданием собственного настраиваемого элемента управления пользовательским интерфейсом.

Помимо этих базовых элементов управления пользовательским интерфейсом, предлагаемых самим Qt Quick, с Qt Quick Controls также доступен богатый набор элементов управления пользовательским интерфейсом. Они удовлетворяют наиболее распространенным случаям использования без каких-либо изменений и предлагают гораздо больше возможностей благодаря своим параметрам настройки. В частности, Qt Quick Controls предоставляет параметры стилизации, которые соответствуют последним тенденциям в дизайне пользовательского интерфейса. Если эти элементы управления пользовательским интерфейсом не удовлетворяют потребностям вашего приложения, только тогда рекомендуется создавать настраиваемый элемент управления.

Дополнительная информация

  • Qt Quick Controls
  • Qt Quick

Рекомендации по кодированию

См. Рекомендации по кодированию 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

Более удобный подход — использование синтаксиса подстановочных знаков qmake для выбора нескольких файлов одновременно:

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. Создание файлов ресурсов подробно описывает, как это сделать.

Дополнительная информация

  • Система ресурсов Qt

Разделение пользовательского интерфейса от логики

Одна из ключевых целей, которую стремятся достичь большинство разработчиков приложений, — создание поддерживаемого приложения. Одним из способов достижения этой цели является разделение пользовательского интерфейса от бизнес-логики. Ниже приведены несколько причин, почему пользовательский интерфейс приложения следует писать на 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
import QtQuick.Controls

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
import QtQuick.Controls

Page {
    Button {
        text: qsTr("Restore default settings")
        onClicked: backend.restoreDefaults()
    }
}

С этим подходом C++ остается неизменным в случае, если QML необходимо переименовать в будущем.

В приведенном выше примере мы устанавливаем свойство контекста в корневом контексте, чтобы экспонировать объект C++ для QML. Это означает, что свойство доступно каждому компоненту, загружаемому движком. Свойства контекста полезны для объектов, которые должны быть доступны сразу после загрузки QML и не могут быть созданы в QML.

Для быстрого руководства по выбору правильного подхода к экспонированию типов C++ для QML см. Выбор правильного метода интеграции между C++ и QML.

Дополнительная информация

  • Интеграция QML и C++
  • Учебник по чат-приложению

Использование Qt Quick Layouts

Qt предлагает Qt Quick Layouts для визуального размещения элементов Qt Quick в макете. В отличие от альтернативы, позиционеров элементов, Qt Quick Layouts также могут изменять размер своих дочерних элементов при изменении размера окна. Хотя Qt Quick Layouts часто являются предпочтительным вариантом для большинства случаев использования, при их использовании необходимо учитывать следующие «следует» и «не следует»:

Следует

  • Используйте anchors или свойства width и height, чтобы указать размер макета по отношению к его родительскому элементу без макета.
  • Используйте присоединенное свойство Layout для установки атрибутов размера и выравнивания непосредственных дочерних элементов макета.

Не следует

  • Не определяйте предпочтительные размеры для элементов, которые предоставляют implicitWidth и implicitHeight, если их неявные размеры не удовлетворяют вас.
  • Не используйте якоря на элементе, являющимся непосредственным потомком макета. Вместо этого используйте 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
            }
        }
    }

Примечание: Макеты и якоря — это типы объектов, которые занимают больше памяти и времени инициализации. Избегайте их использования (особенно в делегатах списков и таблиц, и стилях для элементов управления), когда простые привязки к свойствам x, y, width и height достаточно.

Дополнительная информация

  • Позиционеры элементов
  • Обзор Qt Quick Layouts

Безопасность типов

При объявлении свойств в 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"
}

У него есть следующие недостатки:

  • Он медленный. Свойство цвета сначала вычисляется со значением по умолчанию, а затем — с «красным» позже.
  • Это откладывает ошибки, которые можно найти на этапе сборки, до времени выполнения, замедляя процесс разработки.
  • Это перезаписывает любые декларативные привязки, которые были установлены. В большинстве случаев это предполагается, но иногда это может быть непреднамеренно. См. Отладка перезаписи привязок для получения дополнительной информации.
  • Это мешает инструменту; 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-6.1/qtquick-bestpractices.html

Spec-Zone.ru

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