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