Для организации динамической смены компонентов удобно использовать компонент 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 лоя открытия окон, только для заполнения этих окон контентом.