3

Suppose we have a QML file like the following:

Window {

    Component.onCompleted: rect.color  ="green"

    TabView {
        Tab {
            Rectangle {
                id:  rect
                color: "white"
            }
        }
    }
}

When I run this code, for some reason, it gives me this error:

ReferenceError: rect is not defined

Somebody can say it's a scope problem but the following code works fine:

Window {

    Component.onCompleted: rect.color  ="green"

    Item {
        Item {
            Rectangle {
                id:  rect
                color: "white"
            }
        }
    }
}

In my case I have a big form with tabs and controls inside it and I pass all the controls to several functions to validate the form, i.e. some code like this:

function onClose() {
    validate(control1);
    validate(control2);
    // etc
}

but while accessing controls by id I get the above error.

BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
folibis
  • 12,048
  • 6
  • 54
  • 97
  • `Tab` component is a `Loader` indeed. The components are created only when the tab is active. Try to set active to true and then assign the color you want. – Jairo May 28 '15 at 08:26
  • As said by @Jairo and also from the doc: "Tabs are lazily loaded; only tabs that have been made current (for example, by clicking on them) will have valid content. You can force loading of tabs by setting the active property to true". hence, `active: true` inside the different `Tab`s should solve your problems. – BaCaRoZzo May 28 '15 at 08:49
  • 1
    Nice solution, thanks guys! – folibis May 28 '15 at 09:08
  • I've tried it now and it doesn't work. Although I set `active: true` or put the code into `Component.onCompleted` inside the `Tab`. That only works if I put `Component.onCompleted` inside the item itself, `Rectangle` in the code above. But it's very inconvenient so if you guys know another way to access items inside `Tabs` that would be great. – folibis May 28 '15 at 23:04

2 Answers2

0

How about just binding the rectangle to a color parameter instead of a hardcoded value?

This wil separate your Model and View code further to make it more readable elsewhere in your project as well...try:

Window {

    property string myColor: "White"
    Component.onCompleted: myColor = "Green"

    TabView {
        Tab {
            Rectangle {
                id:  rect
                color: myColor
            }
        }
    }

}

To view the QML object tree, you need to start your project in debug mode. Then split your code window so that the "Locals and Expressions" view is showing (checkbox ticked on the right side). You will see your root item and all the other controls nested in a tree and now you can directly edit the values of their properties, and the changes will render immediately. There is a youtube video tutorial on debugging: https://youtu.be/mPXn6L2Wftc?t=19m55s

I'm not sure if the tree would give you access to the controls at runtime, but it might help you with debugging.

Herald Smit
  • 2,342
  • 1
  • 22
  • 28
  • As I said I have a form with lots of controls, about 40 of them I think. So binding make the code involved and excessive. – folibis May 29 '15 at 14:04
  • You are passing controls around to be validated - what happens when the Views / Forms / Front-end changes? Your validation code will break, and you will need to rewrite it every time you change the form. You need to separate this code from the front-end, so that you can change your complex front-end freely. I would suggest you validate the parameters assigned to the controls, in a separate file even, rather than trying to access the values by iterating through nested controls. It is not like HTML DOM. Good luck! – Herald Smit May 30 '15 at 10:28
  • Thanks for advice dude but it doesn't relate to the questtion. Although it will be build strongly according to MVC, how can I access item insiide `Tab` – folibis May 30 '15 at 23:57
  • I have no problem with debugging I'm more then 6 years with QtCreator but thanks anyway. As for you code - you advice to duplicate all the variables and that is very dirty and non-semantic style of coding. – folibis Jun 02 '15 at 23:08
0

Ok, since Tab item cannot be accessed from outside I think it can be done in this way:

TabView {
    id: tabView
    Tab {
        title: "tab1"
        function validate() { /* validate all the controls related to tab1 only */ }
        Item { id: item1 }
        Item { id: item2 }
    }
    Tab {
        title: "tab2"
        function validate() { /* validate all the controls related to tab2 only */ }
        Item { id: item3 }
        Item { id: item4 }
    }
    function validateTabs() {
        for(var i = 0; i < tabView.count;i ++) {
            var tab = tabView.getTab(i);
            if(tab && tab.active && tab.item.validate) {
                if(!tab.item.validate())
                    return false;
            }
        }
        return true;
    }
}

The good point that if some Tab wasn't opened and so not changed it will not be validated.

folibis
  • 12,048
  • 6
  • 54
  • 97