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".
-
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
active
for 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 theTabView
by objectname.ProxyObject
is just simple class to which we pass the foundTabView
object for further processing. Note that we have usedcontentItem
property as you can see here that allTabs
are 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 theTab
and its child contents for eg.TextField
objects. Once we get hold ofTextField
object, 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 {} } } }