[Qt, Разработка под Linux, Разработка под Windows] Портирование приложений с QWidget на QML под Desktop

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
07-Июл-2020 15:30

Привет, Хабровчане!
Последнее время часто встречаю проекты для desktop, которые необходимо портировать с QWidget на QML. Кто-то хочет написать с нуля, кто-то перенести старые наработки. В любом из сценариев это популяризация QML, чему я очень рад. Я решил тоже побыть полезным и поделиться своими наработками и ситуациями из личной практики. Возможно, некоторые из них покажутся вам простыми и понятными, однако если я что-то упустил, буду рад почитать об этом в комментариях.
Кратко о QML и QWidget
QML — это декларативный язык программирования. Он позволяет разработчикам и дизайнерам создавать удобные, плавно анимированные и визуально привлекательные приложения. QML предлагает читаемый декларативный JSON-подобный синтаксис с поддержкой императивных выражений JavaScript в сочетании с динамическими привязками свойств.
QWidget — это предшествующая QML технология для создания пользовательского интерфейса, основанная на использовании заранее созданных desktop-style компонентов и предоставляющая API для взаимодействия с ними.
Пользовательский опыт
Около года назад я нашел прекрасный инструмент для работы с гитом gitAhead и в целом я доволен большей частью функционала и он мне часто помогает. Но на этом примере прекрасно видно, что виджетам не хватает гибкости и функционала. Из-за этого невозможно покрыть больше пользовательских сценариев и сделать более дружелюбный интерфейс. В итоге вместо отличного дерева коммитов и дифов, мы имеем огромное количество ограничений.

Стандартное окно(кликабельно)

SPL


Дизайн приложения и его влияние на портирование
Классически Qt нам советует придерживаться паттернов MVC\MVP, где всё взаимодействие с UI вынесено в отдельные сущности, что позволяет нам изменять их, не затрагивая остальные части приложений и бизнес логику. Абстрагирование элементов и возможность встраивать QML-компонент в стандартный QWidget позволяет гибко подойти к плану дальнейшей работы. Если вы сейчас на этом пункте, то я бы хотел вам посоветовать продумать требования и функциональность будущего приложения, нарисовать его макет, посоветоваться с дизайнерами, опросить пользователей или заказчика. В целом решить как вы будете жить ближайшее время, и какие вопросы будете решать. И выбрать один из двух путей, предложенных ниже.
План А «С чистого листа»
Мы убираем весь старый UI, виджеты, зависимости, legacy код и оставляем только требования и функциональность, которые нам необходимо будет восстановить. Хорошая возможность улучшить архитектуру, подготовить почву для новых изменений. При подготовке необходимо учитывать следующие вещи, которые изменяются при переходе от одной библиотеке к другой и лучше продумать их заранее:
  • Библиотека элементов. Создайте свою начальную базу элементов, где пропишите базовые настройки для элементов, их вид и состояния по умолчанию. Если есть возможность, оберните их тестами. В одной из конфигураций проекта сделайте их копируемыми в папку проекта, а не компилируемыми в бинарный*.qrc, это позволит вам править эти сборки в runtime без дополнительных компиляций и подключать qmllive и его аналоги.
  • Отсутствие QAction. В приложениях на QWidget, частым гостем является и QAction, расширяющий возможности перехвата действий пользователя как по нажатию кнопки на экране, так и перехватом горячих клавиш. К сожалению в QML QAction переехал в несколько ином виде и позволяет только из QML обертки перехватывать заранее определенные горячие клавиши, что накладывает ограничения на использование его внутри C++ или создавать динамически. Здесь вы можете написать свою реализацию, использовать event-filter от qobject или использовать сторонние проекты, такие как QHotkey.

В остальном здесь всё типично для приложения на C++ и QML.
План Б «У нас типо agile»
Так как для Agile одной из главной ценностью является работающий продукт, то мы должны делать переезд поэтапно, без регресса функционала. Для этого мы делим весь UI на логические сегменты с минимальным количеством взаимозависимостей и реализуем их отдельно. На примере gitAhead можно рассмотреть следующий вариант(выделил зеленым):

Разделение UI на сегменты(кликабельно)

SPL


Для каждой из областей мы создадим родительский виджет, в который и положим корневой QML элемент. Это можно сделать двумя способами.
Создать QQuickWidget
QQuickWidget *view = new QQuickWidget;
view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view->show();

Или вызывать метод QWidget::createWindowContainer(...)
QQuickView *view = new QQuickView();
...
QWidget *container = QWidget::createWindowContainer(view);
container->setMinimumSize(...);
container->setMaximumSize(...);
...
widgetLayout->addWidget(container);

Разница между предложенными способами в том что QQuickWidget является более гибкой альтернативой чем QWidget::createWindowContainer(...), ведя себя больше как обычный QWidget. При этом большая функциональность достигается из-за незначительных потерь в производительности.
Дальнейшая работа производится как с обычным QQuickView, за исключением следующих особенностей:
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 19:10
Часовой пояс: UTC + 5