Search code examples
c++qtqmlqtquick2qtquickcontrols2

How to set currentIndex of SwipeView to currentIndex of TabBar "by reference" after going to specific page?


I'm getting started with QtQuick Controls 2.0. I have experience with C++ and a small amount of experience with Qt, but I have not worked with QML before.

I have a TabBar and a SwipeView that are linked to each other. What I mean by this is that when you select a page on the TabBar, the SwipeView goes to that page. When you swipe to a page from the SwipeView, the TabBar updates itself to reflect that.

As a learning exercise, I decided to create a button that would send the user to the second page. The issue is that I can't seem to find a way to do so without messing up the link between the TabBar and the SwipeView.

The following code is the best I've come up with. It correctly goes to the second page, and when I change the current page with the TabBar the SwipeView still updates. However, swiping to a new page no longer updates the TabBar. It appears that setting tabBar.currentIndex to swipeView.currentIndex only has the effect of setting by reference when done with the colon to initialize. Doing so with an equals sign sets by value. How can I move to a specific page while still maintaining the invariant that swipeView.currentIndex == tabBar.currentIndex?

// main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    SwipeView {
        id: swipeView
        anchors.fill: parent
        currentIndex: tabBar.currentIndex

        Page {
            Button {
                text: qsTr("Continue to Page 2")
                onClicked: {
                    tabBar.currentIndex = 1;
                    // this next line merely sets tabBar.currentIndex to 1
                    tabBar.currentIndex = swipeView.currentIndex
                }
                anchors.centerIn: parent
                width: text.implicitWidth
                height: text.implicitHeight
            }
        }

        Page {
            Label {
                text: qsTr("Second page")
                anchors.centerIn: parent
            }
        }
    }

    footer: TabBar {
        id: tabBar
        currentIndex: swipeView.currentIndex
        TabButton {
            text: qsTr("First")
        }
        TabButton {
            text: qsTr( "Second")
        }
    }
}

The C++ code is simply the default that Qt Creator provided for me:

// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

Solution

  • In order to move to the next or the previous page without breaking the currentIndex bindings, you can call incrementCurrentIndex() or decrementCurrentIndex(), respectively. These methods were introduced in Qt Quick Controls 2.1 in Qt 5.8.

    Given that the currentIndex setter aka. QQuickContainer::setCurrentIndex() is a slot, you can also call setCurrentIndex() from QML to jump to an arbitrary page. This will not break the existing bindings either.

    Button {
        onClicked: tabBar.setCurrentIndex(1)
    }