TabView without lazy loading
-
I have items in a TabView that the parent needs to interact with (e.g. forwarding text from a TextField to C++ for processing then back to QML for displaying in a TextArea) and also update when not the current tab. I understand that the Tab item inherits from Loader and therefore it's children are sort of "sandboxed". Unfortunately, this hinders precisely what I am trying to accomplish. In the QWidget world, all of the items in the TabWidget always exist. Is TabView the best option or should I create my own QTabWidget-like QML component that switches the visibility of items and creates the illusion of "Tabs".
-
I have items in a TabView that the parent needs to interact with (e.g. forwarding text from a TextField to C++ for processing then back to QML for displaying in a TextArea) and also update when not the current tab. I understand that the Tab item inherits from Loader and therefore it's children are sort of "sandboxed". Unfortunately, this hinders precisely what I am trying to accomplish. In the QWidget world, all of the items in the TabWidget always exist. Is TabView the best option or should I create my own QTabWidget-like QML component that switches the visibility of items and creates the illusion of "Tabs".
@ZergedU Hi! I find this really annoying, too. After trying to work around it for some time I eventually implemented my own tabview component.
-
I have items in a TabView that the parent needs to interact with (e.g. forwarding text from a TextField to C++ for processing then back to QML for displaying in a TextArea) and also update when not the current tab. I understand that the Tab item inherits from Loader and therefore it's children are sort of "sandboxed". Unfortunately, this hinders precisely what I am trying to accomplish. In the QWidget world, all of the items in the TabWidget always exist. Is TabView the best option or should I create my own QTabWidget-like QML component that switches the visibility of items and creates the illusion of "Tabs".
Hi @ZergedU,
It can be done from C++ but it involves some child items processing which is fine IMO.I understand that the Tab item inherits from Loader and therefore it's children are sort of "sandboxed".
Not exactly. These can be extracted easily.
Unfortunately, this hinders precisely what I am trying to accomplish. In the QWidget world, all of the items in the TabWidget always exist.
You have the property
activefor Tab which forces Item to exist on load.Here' a minimal example:
main.qml
Item { width: 200 height: 200 TabView { objectName: "tabview" anchors.fill: parent Tab { active: true title: "Tab1" TextField { text: "TextField-One" } } Tab { active: true title: "Tab2" TextField { text: "TextField-Two" } } } }main.cpp
This is where you find theTabViewby objectname.ProxyObjectis just simple class to which we pass the foundTabViewobject for further processing. Note that we have usedcontentItemproperty as you can see here that allTabsare actually parented to it. So,QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("tabview"); QQuickItem *contentItem = qvariant_cast<QQuickItem*>(item->property("contentItem")); ProxyObject *obj = new ProxyObject(contentItem);ProxyObject.cpp
This is where we iterate and get theTaband its child contents for eg.TextFieldobjects. Once we get hold ofTextFieldobject, we can connect its signals for eg.accepted()in this case. The once its correponding slot is invoked we can easily find who the sender was and then further extract its properties.ProxyObject::ProxyObject(QQuickItem *parent) : QObject(parent) { m_item = parent; foreach (QQuickItem *tab, m_item->childItems()) { foreach (QQuickItem *tabitem, tab->childItems()) { connect(tabitem, SIGNAL(accepted()), this, SLOT(onAccepted())); } } } void ProxyObject::onAccepted() { QQuickItem *item = qobject_cast<QQuickItem*>(sender()); qDebug() << item->property("text").toString(); }Hope this helps you in some way :)
-
Thanks for the suggestions everyone! I was really hoping to avoiding having to get involved with C++ just for creating the type of tabview I was looking for. I actually came up with what I think is a pretty neat solution. I used a stackview that I let be only 1 layer deep and disabled the transition animation. Then I connected a custom tab bar to push/pop items onto the stackview. These items to be pushed/popped I stored in a list, meaning they always exist and lazy loading is not used. Below is my attempt to include the code I used. Thanks again everyone!
// Custom components go here, using rectangles just as an example property list<Item> stackViewItems: [ Rectangle{ color: "blue" }, Rectangle{ color: "red" }, Rectangle { color: "green" } ] RowLayout { anchors.fill: parent // Custom component that emits the "tab" index when clicked NavigationMenu { id: navigationMenu // Layout Layout.preferredWidth: 100 Layout.alignment: Qt.AlignTop | Qt.AlignHCenter // Slots onClicked: { stackView.pop() stackView.pushHelper(index) } } StackView { id: stackView // Layout Layout.fillWidth: true Layout.fillHeight: true // Initial Item initialItem: stackViewItems[0] // Helper function pushHelper(index) { if (index >= 0 && index < stackViewItems.length) { push(stackViewItems[index]) } } // Transitions delegate: StackViewDelegate { pushTransition: StackViewTransition {} popTransition: StackViewTransition {} replaceTransition: StackViewTransition {} } } }