CurrentText property of QML Combo box not changing when read from C++ - c++

I am currently using QML/C++ for mobile development and facing a problem that, for sure demonstrates my poor ability to design QML/C++ applications. Hope you can help me here.
This is my main.qml:
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("(Nome da Aplicação)")
header: ToolBar{
RowLayout{
anchors.fill: parent
ToolButton {
id: toolButton
text: stackView.depth > 1 ? "\u25C0" : "\u2630"
onClicked: drawer.open()
}
Label {
text: stackView.currentItem.title
elide: Label.ElideRight
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
Layout.fillWidth: true
}
}
}
Drawer {
id: drawer
width: window.width * 0.33
height: window.height
Column{
anchors.fill: parent
ItemDelegate {
text: qsTr("Operações")
width: parent.width
onClicked: {
stackView.push("Operacoes.qml")
drawer.close()
}
}
ItemDelegate {
text: qsTr("Produtos")
width: parent.width
onClicked: {
stackView.push("Produtos.qml")
drawer.close()
}
}
ItemDelegate {
text: qsTr("Configurações")
width: parent.width
onClicked: {
stackView.push("Configuracoes.qml")
drawer.close()
}
}
}
}
StackView {
id: stackView
initialItem: "Operacoes.qml"
anchors.fill: parent
}
}
The combo box whose value I need to access from C++ is defined in Operacoes.qml which consists of
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import QtCharts 2.3
Item {
objectName: "janelaResumo"
property alias title: paginaOperacoes.title
property alias primeiroGraf: primeiroGraf
property alias segundoGraf: segundoGraf
property alias terceiroGraf: terceiroGraf
property alias quartoGraf: quartoGraf
property alias combo_periodoFaturacao_ID: combo_periodoFaturacao_ID
Page {
id: paginaOperacoes
anchors.fill: parent
title: "Resumo de Operações"
ScrollView {
anchors.fill: parent
clip: true
GridLayout {
id: grid_BaseLayout
columns: paginaOperacoes.width < 400 ? 1 : 2
rows: paginaOperacoes.width < 400 ? 4 : 2
anchors.fill: parent
ColumnLayout {
Label {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Faturação")
font.bold: true
}
RowLayout {
ChartView {
id: primeiroGraf
width: 350
height: 350
antialiasing: true
PieSeries {
name: "PieSeries"
PieSlice {
value: 13.5
label: "Slice1"
}
PieSlice {
value: 10.9
label: "Slice2"
}
PieSlice {
value: 8.6
label: "Slice3"
}
}
}
ComboBox {
objectName: "combo_periodoFaturacao"
model: ListModel{
ListElement {
text:"7 dias"
}
ListElement {
text:"Mensal"
}
ListElement {
text:"Anual"
}
}
id: combo_periodoFaturacao_ID
}
}
}
// segundo gráfico
ColumnLayout {
Label {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Tesouraria")
font.bold: true
}
ChartView {
id: segundoGraf
width: 350
height: 350
antialiasing: true
PieSeries {
name: "PieSeries"
PieSlice {
value: 13.5
label: "Slice1"
}
PieSlice {
value: 10.9
label: "Slice2"
}
PieSlice {
value: 8.6
label: "Slice3"
}
}
}
}
}
}
}
Then, C++ ClassX class implements a method to load data that should start by reading qml interface values in order to use them as arguments for some future processig.
void classX::loadData(){
if(mDbStatus == true){
QQuickView view;
const QUrl url(QStringLiteral("qrc:/Operacoes.qml"));
view.setSource(url);
QObject *OperacoesObject = view.rootObject();
QObject *comboFaturacao_t = OperacoesObject->findChild<QObject ("combo_periodoFaturacao");
qDebug() << comboFaturacao_t->property("currentText");
No matter what value lives in the combobox combo_periodoFaturacao depending on user selection, I always get the same value(first element of the respective combobox model) in comboFaturacao_t->property("currentText");
I am aware that I must avoid referring explicitly my UI from C++!
I also understand that, for each loadData() call, I am instantiating a new QQuickView object, but how can I simply collect a few UI values to serve as parameters for the execution of loadData() without implement a cpp class "binded" to my fileX.qml?

No matter what value lives in the combobox comboFaturacao depending on user selection, I always get the same value(first element of the combobox model)
Based on the code you posted, and except if I missed something, you are reading the value of "currentText" immediately after creating your view, without waiting for the user to select anything. So this will return the initial value when your view is created.
but how can I simply collect a few UI values to serve as parameters for the execution of loadData() without implement a cpp class "binded" to my fileX.qml
Exposing C++ to the UI is really the way to go, and a good practice, which forces to avoid high level logic to GUI dependencies. Which means not depending on implementation detail (GUI in this case). That said, if this is what you want, you can read properties from C++, but still need to wait for the user to be "done", which can be done by:
Creating the view on the heap instead of the stack and saving it somewhere
Connecting a slot like onLoadDataUserSettingsReady to a QML signal, using connect (probably the older SIGNAL/SLOT syntax to allow connecting to an arbitrary signal)
Return from loadData, as you will need to wait for the user to interact with the UI without blocking the main thread
And whenever you emit your QML signal that says "The user is done", your onLoadDataUserSettingsReady slot will be executed, allowing you to read the QML properties you are interested with (or directly pass them in the signal/slot)
But as you can see, this is a bit complex, and forces you to make loadData asynchronous, which may not be what you want. You could potentially make it synchronous using a thread that's not the main thread, and a QSignalSpy or other to wait for a signal, but again, not a great solution. I would still recommend exposing a C++ instance with setContextProperty, and reading from this object in your loadData method, whenever needed.

Related

QML wrapped TableView element behaves different from non-wrapped one

I'm having some troubles getting the QML type TableView to behave correctly when wrapping it inside another item. The problem is that creating a reuseable type basically forces one to use an Item wrapper to have the *HeaderView types in the same .qml file. Here is the rather simple code, a test-model for some data can be taken from the official TableView documentation.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import TableModel
Window {
width: 600
height: 480
visible: true
// This item wrapper changes TableView behavior
Item {
width: 600
height: 250
// --------------------------------------------
TableView {
id: tableView
anchors.fill: parent
topMargin: horizontalHeader.implicitHeight
leftMargin: verticalHeader.implicitWidth
columnSpacing: 1
rowSpacing: 1
clip: true
model: TableModel {}
delegate: Rectangle {
implicitWidth: 150
implicitHeight: 25
Text {
text: display
}
}
}
HorizontalHeaderView {
id: horizontalHeader
syncView: tableView
}
VerticalHeaderView {
id: verticalHeader
syncView: tableView
}
// --------------------------------------------
}
// --------------------------------------------
}
Without the Item wrapper (see comments in code) my TableView looks as expected:
But once wrapped inside an Item the horizontal and vertical headers get placed over the actual table.
For some odd reason this displacement is only relevant for the very first rendering of the table. Once I drag the data from the table around a little (I guess activating the "Flickable" inherited type?) the data suddenly snaps into position and is displayed correctly outside of the headers.
Apparently it wasn't a good idea to use anchors.fill: parent when trying to attach the *HeaderViews. Once I got rid of that line and simply anchored all views to each other (horizontal to top, vertical to left) it works.
Item {
implicitWidth: 600
implicitHeight: 250
TableView {
id: tableView
implicitWidth: parent.implicitWidth
implicitHeight: parent.implicitHeight
anchors.top: horizontalHeader.bottom
anchors.left: verticalHeader.right
columnSpacing: 1
rowSpacing: 1
clip: true
model: TableModel {}
delegate: Rectangle {
implicitWidth: 150
implicitHeight: 25
Text {
text: display
}
}
}
HorizontalHeaderView {
id: horizontalHeader
anchors.left: verticalHeader.right
clip: true
syncView: tableView
}
VerticalHeaderView {
id: verticalHeader
anchors.top: horizontalHeader.bottom
clip: true
syncView: tableView
}
}
Note thougt that in the official Qt docs using anchors inside layouts is explicitly listed as "Don'ts". My guess is that they mean don't use anchors between layout elements or parents of the layout, not don't anchor two elements inside a single layout cell.

Flickering in QML SwipeView

Summary
QML Swipeview has problems updating when model of repeater is reset. The Qt version is 5.12.
Description
Following the doc in (https://doc.qt.io/qt-5/qml-qtquick-controls2-swipeview.html) a SwipeView is implemented. Difference with the example stated in the link, is that no Loader is used. The model of the Repeater is injected by the parent view in form of a QAbstractListModel.
When the viewModel is reset, the SwipeView has problems to update. It causes several repaints of the first page. For the user this appears as if the views is flickering. In the following the QML file and update function of the QAbstractListModel is described.
QML File:
Item {
id: root
/**
Set the model (is of type QAbstractListModel
**/
property var viewModel
height: 30 * Screen.pixelDensity
width: 60 * Screen.pixelDensity
Rectangle {
id: wrapper
anchors.fill: parent
color: "grey"
SwipeView {
id: swipe
clip: true
anchors.fill: parent
Repeater {
model: root.viewModel
Rectangle {
width: 20
height: 20
border.color: "black"
border.width: 1
Text {
text: index
}
}
}
}
}
}
Update Function:
void DerivedQAbstractList::setPages(const std::vector<Pages> &pages)
{
beginResetModel();
// create internal data structure
endResetModel();
}
Observations:
Update problem does not appear when the QAbstractList model is initially empty.
Using the Repeater without a SwipeView works fine (e.g. Column {Repeater {...}}
Do you have any ideas what could be the problem. Or give me an alternative approach to have a swiping view with dynamical model?
Edit 1.0. Using a Instantiator
As asked in the comment, we tried to replace the Repeater with an Instantiator. We can see from the console log, that the components are created. However they do not appear on the screen. What do we miss?
Rectangle {
id: wrapper
anchors.fill: parent
color: "grey"
SwipeView {
id: swipe
clip: true
anchors.fill: parent
Instantiator {
model: root.viewModel
delegate: Rectangle {
Component.onCompleted: console.log("Created")
width: 20
height: 20
border.color: "black"
border.width: 1
Text {
text: index
}
}
}
}
}

How to create Material Design navigation drawer in Qt using qml

I'm trying to create a navigation drawer like the image below:
First I tried it with ListView
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Layouts 1.12
ApplicationWindow{
id: window
visible: true
width: 640
height: 480
title: "Dashboard"
Material.theme: Material.Light
Material.primary: "#1de9b6"
Material.accent: "#3d5afe"
header: ToolBar{
RowLayout{
anchors.fill: parent
ToolButton{
id: btnDrawer
icon.source: "qrc:/icons/icons/ic_drawer.svg"
onClicked: {
if(!navDrawer.opened)
navDrawer.open()
if(navDrawer.opened)
navDrawer.close()
}
}
Item{
Layout.fillWidth: true
}
ToolButton{
id: btnUsuario
icon.source: "qrc:/icons/icons/ic_bullet_menu.svg"
}
}
}
Drawer{
id: navDrawer
y: header.height
width: window.width / 3
height: window.height - header.height
ListView{
model: ListModel{
ListElement{
icon: "qrc:/icons/icons/ic_people.svg"
name: "Hopsede"
}
}
delegate: Item{
Image{
source: icon
}
Text{
text: name
}
}
}
}
}
And this is the result:
Not cool. Now i tried using Layouts
Almost good, but still not clickable and not hoverable effect, now finaly i tried used buttons:
This time it was far from looking like a navigation drawer, I intend to make the entire desktop application using material design for having a good appearance, but I'm not able to replicate some components like this
Your root delegate item has no size, which is why everything is jumbled together. The docs for ListView say:
The ListView will lay out the items based on the size of the root item
in the delegate.
So you need to either give it a size, or use an item that has an implicit size, like ItemDelegate:
delegate: ItemDelegate {
text: model.name
width: parent.width
icon.source: model.icon
}
Note that in that example, the width is set so that it takes up the entire ListView. If you don't do that, it will still have a valid size, it will just likely be too small.
You probably also want to make the ListView fill the Drawer:
anchors.fill: parent

Qt5 - QML: Button does not show up after triggered

I am writing a project that is using Qt5-QML. In order to shrink the problem I prepared a small example that replicates the problem.
1) I have an application on a Page1. That carries a Button as shown in the below print screen below:
2) After the user pushes the button goes on Page2 shown below which carries different Buttons. Let's say Button A it is the user's choice:
3) The final screen represented by Page1 is the correct choice, which is the the button selected
The problem I have is that after the user selects the choice on point 2) and goes back on Page1 a Button should appear on Page1 in the middle of the Page1 that opens a dialog window, in my case a WebEngineView only related to that Button.
Of course if the user selcts Button 3 on Page2, back on Page1 there should be another Button that opens another dialog related to Button 3 and that is always a WebEngineView.
I can't see the Button and the related dialog.
The expected result is the print screen below:
Below the snippet of code that carries the problem:
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Conn")
property Page1 page1: Page1 {}
property Page2 page2: Page2 {}
Component.onCompleted: {
page2.onButtonClicked.connect(function(buttonId, buttonName) {
page1.mytext.text = buttonId;
page1.mytext.text = buttonName;
mystackview.pop();
});
}
// These buttons should appear only after the user selects the choices on `Page2`
Button {
id: dialogA
Layout.fillWidth: true
text: "Open Dialog A"
}
Button {
id: dialogB
Layout.fillWidth: true
text: "Open Dialog B"
}
Button {
id: dialogC
Layout.fillWidth: true
text: "Open Dialog C"
}
StackView {
id: mystackview
anchors.fill: parent
initialItem: page1
}
}
page1.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Page {
property alias mytext: mytext
Button {
id: button1
text: "Select"
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
onClicked: {
mystackview.push(page2);
}
}
Text {
id: mytext
anchors.top: button1.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
font.bold: true
font.pointSize: 30
}
}
page2.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Page {
signal onButtonClicked(var buttonId, var buttonName)
Component.onCompleted: {
button1.clicked.connect(function() {
onButtonClicked(1, "A");
});
button2.clicked.connect(function() {
onButtonClicked(2, "B");
});
button3.clicked.connect(function() {
onButtonClicked(3, "C");
});
}
ColumnLayout {
id: mybuttons
anchors.fill: parent
spacing: 5
Button {
id: button1
Layout.fillWidth: true
Layout.fillHeight: true
text: "A"
}
Button {
id: button2
Layout.fillWidth: true
Layout.fillHeight: true
text: "B"
}
Button {
id: button3
Layout.fillWidth: true
Layout.fillHeight: true
text: "C"
}
}
What I tried so far:
1) I came across the following source which was useful to understand the style of a component. And that is for this reason that I used Component.onCompleted: on my code. Which did a good job in triggering the buttons at Page2. I thought that I could use the same philosophy also for the others but they are not showing up.
2) This source was useful for me to understand the properties of a components, in particular in the example how to highlight on a click. I think this is the most close that I can find for what I am doing.
3) Digging more in what I am trying to achieve I went ahead and went through the official documentation which seems to push for the use of the property onCurrentItemChanged which could be a choice as triggers the emit properties of a signal.
UPDATES
The following part in the main.qml is used to show that once the user triggers one of the three buttons, then on page1 it is shown the letter of the Button that was clicked, in fact it is possible to see it on point 3) of the procedure.
Component.onCompleted: {
page2.onButtonClicked.connect(function(buttonId, buttonName) {
page1.mytext.text = buttonId;
page1.mytext.text = buttonName;
mystackview.pop();
});
This is connected to the signal on the page2.qml as shown below:
signal onButtonClicked(var buttonId, var buttonName)
Why I can't see the Button after I go back on Page1 of my QML application?
Thank you very much for pointing in the right direction to solve this problem.
As mentioned in my comment, the "Open Dialog" buttons are always hidden by the stack view anyway. If they weren't hidden by that, they'd in any case need some flag to indicate whether they should be visible or not, based on the selection made on Page2.
Keeping with the existing structure of your MRE, here's one way it could work. I've moved the "Open Dialog" buttons to Page1 because that seems to make the most sense, but they could also be on some separate page, or incorporated into main.qml if there were some layout there which allowed that. Also I made a signal/slot connection from Page1 to trigger the Page2 load in main.qml (instead of directly trying to access objects in main.qml, which is bad practice). I also removed the text label from Page1 to simplify the code. Page2 code remains unchanged so I do not include it.
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Conn")
property Page1 page1: Page1 {}
property Page2 page2: Page2 {}
Component.onCompleted: {
page1.selectDialog.connect(function() {
mystackview.push(page2);
});
page2.onButtonClicked.connect(function(buttonId, buttonName) {
page1.dialogId = buttonId;
mystackview.pop();
});
}
StackView {
id: mystackview
anchors.fill: parent
initialItem: page1
}
}
Page1.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Page {
property int dialogId: -1;
signal selectDialog()
ColumnLayout {
anchors.fill: parent
spacing: 5
Button {
id: button1
text: "Select"
onClicked: selectDialog()
Layout.fillWidth: true
}
// These buttons should appear only after the user selects the choices on `Page2`
Button {
id: dialogA
text: "Open Dialog A"
visible: dialogId === 1
Layout.fillWidth: true
}
Button {
id: dialogB
text: "Open Dialog B"
visible: dialogId === 2
Layout.fillWidth: true
}
Button {
id: dialogC
text: "Open Dialog C"
visible: dialogId === 3
Layout.fillWidth: true
}
}
}

Change children property when parent property changes in QML

I have 3 files. main.qml, Guide.qml and ChannelViewer.qml
my main class contains 2 components and a loader here is the code
main.qml
import QtQuick 2.0
Rectangle {
id:loader
color: "black"
property string channelName
property string channelURL
Component{
id:tv
ChannelViewer{}
}
Component{
id:guide
Guide{}
}
Loader
{
id: pageLoader
anchors.fill:parent
focus:true
sourceComponent: tv
}
Connections{
target:pageLoader.item
onChangeChannel:{
channelName=name
channelURL=url
}
}
Keys.onPressed: {
event.accepted = true;
if (event.key === Qt.Key_I) {
pageLoader.sourceComponent = tv;
}
else if(event.key === Qt.Key_G) {
pageLoader.sourceComponent = guide;
}
}
}
Now if I press "G" I would be moved to the guide file without any issues In my guide page I am able to send signal to main.qml and update the name property in main.
Guide.qml
Item {
signal changeChannel(string url, string name)
Loader {
id: pageLoader
anchors.fill:parent
sourceComponent: guide
focus:true
}
Keys.onPressed: {
if(event.key === Qt.Key_Escape) {
pageLoader.source = "main.qml";
}
event.accepted = true;
}
Component {
id:guide
Rectangle {
color:"lightblue"
Keys.onPressed: {
if(event.key === Qt.Key_Return) {
changeChannel(menuContent.currentItem.ch_url, menuContent.currentItem.ch_name)
pageLoader.source = "main.qml";
}
event.accepted = true;
}
}
}
}
However now when I press "Return" in my Guide.qml i will be taken back to main.qml (Channelname and ChannelURL will be updated successfully), and my main.qml will now take me to ChannelViewer.qml and here is the problem my ChannelViewer.qml will not receive the updated channelName and channelURL. And I am not sure what am I doing wrong.
ChannelViewer.qml
import QtQuick 2.0
import VLCQt 1.0
Rectangle {
id:root
width: 640
height: 480
color: "black"
focus:true
Loader
{
id: pageLoader
anchors.fill:parent
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(channelURL)
}
}
Keys.onPressed: {
if (event.key === Qt.Key_I) {
event.accepted = true;
if(channelInfo.visible === true) {
channelInfo.visible=false;
}
else {
channelInfo.visible=true;
}
}
}
VlcVideoPlayer {
id: vidwidget
anchors.fill: parent
url:channelURL
ChannelInfo{
id:channelInfo
anchors.bottom: parent.bottom
anchors.bottomMargin: ((parent.height*5)/100)
anchors.horizontalCenter: parent.horizontalCenter
width:parent.width - ((parent.width*10)/100)
height: (parent.height*20)/100
backgroundOpacity: 0.7
radius:10
channelNameProp: channelName
channelNumberProp: "1"
headerIcon: "imgs/television_32x32.png"
}
}
}
EDIT:
Code for my ChannelInfo.qml
import QtQuick 2.0
Item {
id:channelinfo
property color backgroundColor: "blue"
property color headerBackgroundColor: "lightblue"
property color headerNameColor: "black"
property color borderColor: "black"
property color channelNameColor: "white"
property color channelNumberColor: "white"
property real borderWidth:0
property real radius:0
property real backgroundOpacity: 0.5
property string menuTitle : "TV Channels"
property string channelNameProp
property string channelNumberProp
property url headerIcon: "imgs/television.png"
visible:false
Rectangle{
id:root
width:channelinfo.width
height:channelinfo.height
color:channelinfo.backgroundColor
border.color:channelinfo.borderColor
border.width: channelinfo.borderWidth
radius:channelinfo.radius
opacity:channelinfo.backgroundOpacity
visible: parent.visible
Rectangle{
id:header
anchors.top:parent.top
// width:(parent.width*40)/100
width: parent.width
height: (parent.height*30)/100
radius: channelinfo.radius
color:channelinfo.headerBackgroundColor
Image{
source:channelinfo.headerIcon
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -4
}
Text{
id:headerTitle
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
width:parent.width
wrapMode: Text.WordWrap
color:channelinfo.headerNameColor
text:menuTitle
font.pixelSize: Math.round(parent.height/2)
font.bold: true
}
}
Rectangle{
id:content
anchors.bottom: parent.bottom
width:parent.width
height:parent.height-header.height
color:"transparent"
Text{
id:channelName
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
color:channelinfo.channelNameColor
text:channelNameProp
font.pixelSize: Math.round(parent.height/4)
font.bold: true
}
Text{
id:channelNumber
anchors.right: parent.right
anchors.rightMargin: 20
anchors.verticalCenter: parent.verticalCenter
color:channelinfo.channelNumberColor
text:channelNumberProp
font.pixelSize: Math.round(parent.height/4)
font.bold: true
}
}
}
}
Github Page for VLCPlayer
https://github.com/vlc-qt/
If you are going to have such a fixed structure, why even bother with the signal, you can simply:
Keys.onPressed: {
if(event.key === Qt.Key_Return) {
channelName = menuContent.currentItem.ch_name
channelURL = menuContent.currentItem.ch_url
pageLoader.source = "main.qml";
}
event.accepted = true;
}
And then remove the unnecessary part:
Connections{
target:pageLoader.item
onChangeChannel:{
channelName=name
channelURL=url
}
}
Since channelName and channelURL are declared in the root object of the qml file, they should be accessible from within objects that are nested further up the tree because of dynamic scoping.
So after you posted the relevant code, you have an:
Text{
id:channelName
in your ChannelInfo object, which is shadowing the channelName property, declared in main.qml. It is a good idea to develop the habit of consistent naming conventions. For example, since this is an id, I personally would have used id: _cName, this way you minimize the odds of getting such collisions.
Update:
The only other reason I can think why it doesn't work is that you are somewhere breaking the channelNameProp: channelName binding by doing something like channelNameProp = something.
Here is a quick example to illustrate that dynamic scoping just works (as long as you don't shadow anything), even in situations that involve dynamically changing Loader items:
// main.qml
ApplicationWindow {
id: _cName
visible: true
width: 640
height: 480
property int value: 0
Loader {
id: loader
source: "Obj.qml"
}
}
// Rect.qml
Rectangle {
id: rectangle
width: 50; height: 100
color: "red"
Text {
anchors.centerIn: parent
text: value
}
MouseArea {
anchors.fill: parent
onClicked: {
loader.source = "Obj.qml"
}
}
}
// Obj.qml
Rectangle {
id: rectangle
width: 50; height: 100
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
value++
loader.source = "Rect.qml"
}
}
}
As the properties
property string channelName
property string channelURL
have change signals and therefore support property binding, I think the easiest way would be to change line 9-17 to
Component{
id:tv
ChannelViewer {
id: channelViewer
channelName: loader.channelName
channelURL: loader.channelURL
}
}
Component{
id:guide
Guide {
id: guide
channelName: loader.channelName
channelURL: loader.channelURL
}
}
If Guide changes the channelName you need to make sure that you change it in the loader. You might use Binding-objects to make the bindings survive assignments (=).
So this works, you need to create the properties channelName and channelURL in the root nodes of your Guide.qml abd your ChannelViewer.qml. Then, in each place inside those files, you use fully qualified identifiers: id.propertyName, which would be e.g channelinfo.channelName in the ChannelInfo.qml, root.channelName in the ChannelViewer.qml and an id you will need to set (e.g. root again) in your Guid.qml -> root.channelName.
Usage of fully qualified identifiers for bindings, which always include the idOfTheObject.propertyName helps to avoid problems. In some cases (positioning, anchoring, sizing) parent is ok, but you might not know what exactly is the parent)
Dynamic scoping is a blessing if you know exactly how and where the code will be used, e.g. if it is essentially a partial definition of a larger object, and will never be used in another context. But here you need to know that if the parent file changes the internal api, you need to adapt the child file accordingly. If you think, the file might be for reuse, avoid dynamic scoping and only reference what is defined inside the file.