Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Forum Updated on Feb 6th

    Unsolved TabView without lazy loading

    QML and Qt Quick
    3
    4
    1531
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Z
      ZergedU last edited by

      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".

      ? p3c0 2 Replies Last reply Reply Quote 0
      • ?
        A Former User @ZergedU last edited by

        @ZergedU Hi! I find this really annoying, too. After trying to work around it for some time I eventually implemented my own tabview component.

        1 Reply Last reply Reply Quote 0
        • p3c0
          p3c0 Moderators @ZergedU last edited by

          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 the TabView by objectname. ProxyObject is just simple class to which we pass the found TabView object for further processing. Note that we have used contentItem property as you can see here that all Tabs 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 the Tab and its child contents for eg. TextField objects. Once we get hold of TextField 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 :)

          157

          1 Reply Last reply Reply Quote 0
          • Z
            ZergedU last edited by

            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 {}
                        }
                    }
                }
            
            1 Reply Last reply Reply Quote 0
            • First post
              Last post