Для організації динамічної зміни компонентів зручно використовувати компонент Loader, який входить у QML QtQuick і є контейнером для ваших компонентів у додатку, який допустимо необхідно періодично замінювати в інтерфейсі.
Якщо провести аналогію, наприклад, з розробкою на Java під Android, там є система фрагментів, які також можуть замінюватися в контейнері для них, слідуючи логіці програми, що розробляється. Допустимо, Ми клацаємо на кнопку і в певному контейнері у нас замінюється один фрагмент іншим, а якщо клацаємо на іншу кнопку, то з'являється третій фрагмент, який замінює другий фрагмент собою.
Тому зробимо додаток, який матиме 5 кнопок і натисканням кожної кнопки в Loader будуть змінюватися фрагменти.
Структура проекту для роботи з Loader
- QmlLoader.pro - профайл проекту;
- main.cpp - основний файл вихідних кодів програми;
- main.qml - основний файл кодів qml;
- Fragment1.qml - перший фрагмент для заміни в Loader;
- Fragment2.qml - другий фрагмент;
- Fragment3.qml - третій фрагмент.
main.cpp створюється за замовчуванням і не змінюється, тому його лістинг наводиться не буде, так само як і профайлу проекту.
main.qml
Установка компонентів Loader може здійснюватися декількома способами:
- Через властивість source - у цьому випадку компонентом є файл QML та його вміст обмежений областю видимості у плані взаємодії з іншими елементами у файлі main.qml;
- Через властивість sourceComponent - в даному випадку встановлюються об'єкти Component, які містяться у файлі main.qml та не обмежені областю видимості при взаємодії з іншими об'єктами у main.qml;
- Встановлення через метод setSource() - в даному випадку є можливість задати додаткові параметри для об'єкта, наприклад рівень непрозорості, але не забувайте ці параметри встановлювати заново, інакше вони зберігаються навіть при установці нового компонента.
У наведеному нижче коді є шар з п'ятьма кнопками, об'єктом Loader , який є прямокутним контейнером, в який будуть розміщуватися наші фрагменти. Робота з розташуванням його у вікні програми виконується так, ніби це об'єкт типу Rectangle .
import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.1 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") // Слой с кнопками, которые будут менять фрагменты RowLayout { id: rowLayout anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.margins: 5 Button { text: qsTr("Фрагмент 1") // Загрузка компонента из файла onClicked: loader.source = "Fragment1.qml" } Button { text: qsTr("Фрагмент 2") // Загрузка компонента через метод setSource с установкой параметров фрагмента onClicked: loader.setSource("Fragment2.qml", {"opactity": 1 }) } Button { text: qsTr("Фрагмент 3") // Загрузка компонента через метод setSource с установкой параметров фрагмента onClicked: loader.setSource("Fragment3.qml", {"opacity": 0.5}) } Button { text: qsTr("Фрагмент 4") // Установка фрагмента из объекта Component onClicked: loader.sourceComponent = fragment4 } Button { text: qsTr("Фрагмент 5") // Установка фрагмента из объекта Component onClicked: loader.sourceComponent = fragment5 } } // Loader для загрузки фрагментов Loader { id: loader anchors.top: rowLayout.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.topMargin: 5 source: "Fragment1.qml" } // Четвёртый фрагмент в качестве компонета Component { id: fragment4 Rectangle { anchors.fill: parent color: "blue" Text { text: "Fragment 5" color: "white" anchors.top: parent.top anchors.right: parent.right anchors.margins: 50 font.pixelSize: 30 renderType: Text.NativeRendering } } } // Пятый фргамент в качестве компонента Component { id: fragment5 Rectangle { anchors.fill: parent color: "black" Text { text: "Fragment 5" color: "white" anchors.top: parent.top anchors.right: parent.right anchors.margins: 50 font.pixelSize: 30 renderType: Text.NativeRendering } } } }
Fragment1.qml та інші фрагменти
Код Fragment1.qml та інших фрагментів ідентичний крім того, що вони мають різний колір фону.
import QtQuick 2.5 Rectangle { anchors.fill: parent color: "green" Text { text: "Fragment 1" color: "white" anchors.top: parent.top anchors.right: parent.right anchors.margins: 50 font.pixelSize: 30 renderType: Text.NativeRendering } }
Підсумок
Після того, як Ви скомпонуєте вище написаний код, у Вас вийде програма, яка буде виглядати так, як показано на наступному рисунку. Демонстрацію роботи програми Ви можете побачити у відеоуроці.
Добрый день интересует такой вопрос. С помощью QML возможно ли создавать многооконные приложения? Есть ли аналоги MDI area? Гугл не помогает, в документации только однооконные приложения с регистрацией в main.cpp. Какая практика вообще существует использования qml в создании больших приложений (многооконных).
День добрый!!
В QML нет аналога MDI area, но можно сделать стандартный проект на QWidget, добавить в главное окно QMdiArea, а в него добавлять QML-ки в качестве виджетов через QQuickWidget. Вот статья для примера, как отобразить виджет с QML в проекте на QWidget .
Вот и я тоже пришел к такому же выводу, стандартное QWidget как обертка для QuickWidget-ов. А вообще практика применения QML для десктопов видимо такая же, я не нашел информации на этот счет вообще .
Я не встречался с повсеместным использованием QML для десктопа, если приложение также не затачивается на работу под мобильные платформы. Видимо, поэтому и MDI area до сих пор не существует для QML, поскольку имеет крайне низкий приоритет.
Добрый день! Благодарю за хороший пример, только его бы дополнить немного: что если мне нужно из фрагментов "Fragment 1.qml" - "Fragment 2.qml" посылать сигналы, причём набор сигналов разный. Как это лучше организовать, какие тут есть варианты?
P.S. Сам спросил - сам отвечаю: :)
Another variant: move above logic inside
and call these functions via property like this:Добрый день. Не успел Вам ответить ))
Для ответа на ваш вопрос, по моему мнению лучше было бы объединить всю информациб о сигналах и слотах, которая присутсвует на сайте.
Поэтому я первоначально потратил время на подготовку статьи, касательно вашего вопроса.
Можете прочитать здесь QML - Урок 036. Работа с сигналами и слотами в QML .
Надеюсь, что найдёте ещё что-нибудь дополнительное для себя.
Благодарю!
Всем привет. А есть ли возможность динамически загрузить qml файл, который скачивается во время работы программы и помещается в определённую папку на диске C?
Да можно, нужно указать относительный путь к qml файлу
добрый день, грамотно ли использовать loader для загрузки небольших диалоговых окон по клику из меню? и если да, то возникает проблема: загрузили первое диалоговое окно, потом его закрыли, а открыть снова получается только после згразки другого д.о. Проблема в свойтве status?
Лично для меня loader - это компонень, который загружает какую-то часть внутри окна, поэтому с этой точки зрения я бы не стал рассматривать использование loader лоя открытия окон, только для заполнения этих окон контентом.