Is there any alternative of loader in qml? - qt

Actually some of function of my program stopped when I use asynchronous keyword in loader so is there any alternative of loader or asynchronous in qml?

Here are 3 example for loading component
//1-loading using loader
//2-loading component without loader
//3-loading qml without loader
Window {
id:appWindow
width: 300; height: 100; visible: true
property Component cmpontnt:Rectangle{
width: 10
height: 20
color: "red"
}
Loader{
sourceComponent: cmpontnt//1-- loading through loader
}
Component.onCompleted:{
//2-- loading component using createObject
cmpontnt.createObject(appWindow, {x: 50, y: 50});
//3--creating component from .qml and loading using createObject
var component2 = Qt.createComponent("TestCmp.qml");
component2.createObject(appWindow, {x: 80, y: 50});
}
}

Related

how to load component from another file using loader in qml

I am using loader to load another qml file and after that file is loaded i am trying to set the component of it. The problem is that qml does not recognize the name of component as it is defined in another file.
I know if i make the component it can recognize and loads it using loader. But what i am trying to do is trying to load the component from another file using loader. Please help me Thank you.
Inside main.qml
MouseArea {
anchors.fill: parent
onClicked: {
display.visible = false
loader.source = "second.qml"
loader.sourceComponent = secondcomp
}
}
second.qml
import QtQuick 2.0
Component {
id : secondcomp
Rectangle{
id : display
x: 0
y: 100
visible: true
width: 100
height: 100
color: "red"
}
}
by setting secondcomp as property and making it alias to be used in other file
Item{
id : main
property alias secondcomp: secondcomp
Component {
id : secondcomp
Rectangle{
id : display
signal message(string msg)
x: 400
y: 400
visible: true
width: 100
height: 100
color: "red"
}
}
MouseArea {
anchors.fill: parent
onClicked: secondcomp.message("clicked!")
}
}
and making main.qml
MouseArea {
anchors.fill: parent
onClicked: {
display.visible = false
loader.source = "second.qml"
loader.sourceComponent = loader.item.secondcomp
}
}

QML: How to custom a component and use it in same file

Is there some syntax in QML to define and use a component in same file like this?
import QtQuick 2.6
import QtQuick.Window 2.2
var MyButton = Rectangle { width : 100; height : 60; color : "red" } // define it
Window {
visible: true
MyButton // use it
}
You can't really use an inline component directly, but you could use a loader:
Component {
id: btn
Button { width = 100; height = 60; background = "red" }
}
Loader {
sourceComponent: btn
}
Another downside is this way you cannot directly specify properties for the created object.
You can also use the component as a delegate for views and repeaters and such.
This is IMO one of the big omissions of QML.
Update: I just noticed this answer a bit out of date. Qt has had inline components for a while. Keep in mind they still have many bugs, there's stuff that will work in a regular component that will not work in an inlined one, especially around inline component properties in other inline components, property aliases and such. If you get some weird behavior, just remember to test it out standalone as well:
component Custom : Item { ...new stuff... }
... in the same source
Custom { }
Also note that it has to be put inside some qml object, it cannot be just a source code global as with JS files.
Powered by #dtech
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Component { id: btn; Rectangle { width : 100; height : 100; color : "red" } }
Column {
spacing: 10
Loader { sourceComponent: btn }
Loader { sourceComponent: btn; width: 300 }
Loader { sourceComponent: btn; width: 1000 }
}
}
And the result:

QML BusyIndicator while loading a heavy qml file

I've been trying to run a BusyIndicator (http://doc.qt.io/qt-5/qml-qtquick-controls-busyindicator.html) while I am loading a qml file (http://doc.qt.io/qt-5/qml-qtquick-loader.html), but the BusyIndicator doesn't appear.
What I am trying to do is:
1- The user emits a "handlerLoader(name)", where "name" is the url of the next qml page.
2- In "onHandlerLoader" I run the busyIndicator.
3- Then, I change the Loader source.
The problem is that no matter the time I spent between steps 2 and 3, the BusyIndicator does not appear.
Moreover, when I comment step 3, the busyIndicator appears correctly.
What I am doing wrong?
Thanks!!
This is the code:
Rectangle {
visible: true
width: 800
height: 480
signal handlerLoader (string name)
Loader {
id: pageLoader;
source: "init.qml";
}
BusyIndicator {
id: busyIndicator_inicio
width: 100
height: 100
anchors.centerIn: parent
running: false
}
Connections {
target: pageLoader.item
onHandlerLoader: {
busyIndicator_inicio.running = true
pageLoader.source = name;
}
}
}
The reason is, that your heavy-loading Loader is blocking the thread.
Set it to asynchronous mode, to allow the rest of the program to run.
Further, I'd recommend to prefer declarative bindings to imperative assignments in handlers. See my example:
main.qml:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
width: 1000
height: 800
visible: true
Button {
text: 'load'
onClicked: {
loader.source = "TestObj.qml"
}
}
Loader {
anchors.fill: parent
id: loader
active: true
asynchronous: true
visible: status == Loader.Ready
}
BusyIndicator {
id: ind
anchors.fill: parent
running: loader.status == Loader.Loading
}
}
TestObj.qml:
import QtQuick 2.0
Item {
Grid {
anchors.fill: parent
columns: width
rows: height
Repeater {
model: 100
Rectangle {
width: { for (var i = 0; i < 10000; i++) console.log(i); return 1 }
height: 1
color: 'green'
}
}
}
}
Since the asynchronous Loader might display incomplete files for some time, I set it to be visible only when its status changes to ready.

Qt 5: read property inside Loader

How to read property timeout located inside Loader object in Qt5 QML Quick 2.0?
import QtQuick 2.0
Rectangle {
width: 100
height: 100
color: "black"
property Component comp1 : Component {
Rectangle {
id: abc
property int timeout: 5000
width: 10; height: 10;
color: "red"
}
}
Loader {
id: loader
sourceComponent: comp1
}
Component.onCompleted: console.log( "timeout: " + loader.item.abc.timeout )
}
TypeError: Cannot read property 'timeout' of undefined
You have a few issues in your code, namely:
1) You do not assign an id identifier to your component object.
2) You are trying to inherit Component with a property which is needless in this simple code.
3) You do not use the item property properly for the Loader element.
4) You are referring to a property name rather the id of the Component. This is again back to the needless inheritance.
Based on the official documentation, you should be doing something like this:
import QtQuick 2.0
Rectangle {
width: 100
height: 100
color: "black"
Component {
id: comp1
Rectangle {
id: abc
property int timeout: 5000
width: 10; height: 10;
color: "red"
}
}
Loader {
id: loader
sourceComponent: comp1
}
Component.onCompleted: console.log( "timeout: " + loader.item.timeout )
}

Add elements dynamically to SplitView in QML

I am working with QML and I want to add elements to SplitView dynamically eg. onMouseClick, but so far I didn't find the answer.
What I've found out so far is that the SplitView has it's default property set to it's first child's data property. So I guess I should try and add new dynamically created components with the parent set to that child (splitView1.children[0]). Unfortunately that doesn't work either. What is more the number of children of that first child is zero after the component has finished loading (seems like the SplitLayout's Component.onCompleted event calls a function that moves those children somewhere else). Thus the added children do not render (and do not respond to any of the Layout attached properties).
Please see the following code snippet:
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
ApplicationWindow {
width: 600
height: 400
SplitView {
anchors.fill: parent
Rectangle {
id: column
width: 200
Layout.minimumWidth: 100
Layout.maximumWidth: 300
color: "lightsteelblue"
}
SplitView {
id: splitView1
orientation: Qt.Vertical
Layout.fillWidth: true
Rectangle {
id: row1
height: 200
color: "lightblue"
Layout.minimumHeight: 1
}
// Rectangle { //I want to add Rectangle to splitView1 like this one, but dynamicly eg.onMouseClick
// color: "blue"
// }
}
}
MouseArea {
id: clickArea
anchors.fill: parent
onClicked: {
console.debug("clicked!")
console.debug("len: " + splitView1.__contents.length); // __contents is the SplitView's default property - an alias to the first child's data property
var newObject = Qt.createQmlObject('import QtQuick 2.1; Rectangle {color: "blue"}',
splitView1, "dynamicSnippet1"); //no effect
// var newObject = Qt.createQmlObject('import QtQuick 2.1; import QtQuick.Layouts 1.0; Rectangle {color: "blue"; width: 50; height: 50}',
// splitView1, "dynamicSnippet1"); //rectangle visible, but not in layout(?) - not resizeable
}
}
}
Is there any way I can make the dynamically created components render properly in the SplitView as the statically added ones?
It appears that the API does not provide support for dynamic insertion of new elements. Even if you do get it to work it would be a hack and might break with future releases. You may need to roll your own control to mimic the behavior you want. Ideally it should be backed by some sort of model.
As of QtQuick Controls 1.3, SplitView has an addItem(item) method.
you have to use the Loader for load dinamicaly objects. in onClicked handle you have to declare sourceComponent property to change the source of the Loader, something like this:
ApplicationWindow {
width: 600
height: 400
SplitView {
anchors.fill: parent
Rectangle {
id: column
width: 200
Layout.minimumWidth: 100
Layout.maximumWidth: 300
color: "lightsteelblue"
}
SplitView {
id: splitView1
orientation: Qt.Vertical
Layout.fillWidth: true
Rectangle {
id: row1
height: 200
color: "lightblue"
Layout.minimumHeight: 1
}
Loader {
id:rect
}
}
}
MouseArea {
id: clickArea
anchors.fill: parent
onClicked: {
console.debug("clicked!")
console.debug("len: " + splitView1.__contents.length) // __contents is the SplitView's default property - an alias to the first child's data property
rect.sourceComponent = algo
}
}
Component {
id:algo
Rectangle {
anchors.fill: parent
color: "blue"
}
}
}
I saw the source code of SplitView, it calculate each split region when Component.onCompleted signal. So I think that is a key point. No matter how you do (insert, dynamic create). The region won't be reset after you insert a new region for split.

Resources