Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Drawer as child inside a SwipeView



  • So, I have found a strange behavior when I was trying to use a Drawer inside a interface with SwipeView-based navigation.

    The goal was to have a side menu but on only one page inside of the SwipeView, so that it would not appear when other pages are shown to the user. Here is a sample project that is based on Qt Creator's "Application Qt Quick - Swipe" template (Page1/2Form.ui.qml are not used).

    main.qml:

    import QtQuick 2.9
    import QtQuick.Controls 2.2
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Tabs")
    
        SwipeView {
            id: swipeView
            anchors.fill: parent
            currentIndex: tabBar.currentIndex
    
            MyPage {
    
                Label {
                    anchors.centerIn: parent
                    text: "Page 1"
                    color: "white"
                }
    
                Item {
                    id: drawerContainer
                    anchors.fill: parent
    
                    Drawer {
                        id: drawer
                        width: 0.33 * parent.width
                        height: parent.height
                        parent: drawerContainer
                        background: Rectangle {
                            color: "red"
                        }
    
                        Label {
                            text: "Content goes here!"
                            anchors.centerIn: parent
                        }
                    }
    
                }
            }
    
            MyPage {
                Label {
                    anchors.centerIn: parent
                    text: "Page 2"
                    color: "white"
                }
            }
    
            MyPage {
                Label {
                    anchors.centerIn: parent
                    text: "Page 3"
                    color: "white"
                }
            }
        }
    
        footer: TabBar {
            id: tabBar
            currentIndex: swipeView.currentIndex
    
            TabButton {
                text: qsTr("Page 1")
            }
            TabButton {
                text: qsTr("Page 2")
            }        
            TabButton {
                text: qsTr("Page 3")
            }
        }
    }
    

    MyPage.qml:

    import QtQuick 2.9
    import QtQuick.Controls 2.2
    
    Page {
        id: root
        // Title in status bar for navigation
        title: qsTr("Main page")
        
        background: Rectangle {
            color: "black"
        }
        // Top status bar for service info output
        header: Rectangle {
            color: "red"
        }
    
    }
    

    So, the key line is parent: drawerContainer which re-parents Drawer element to an Item that is a child of the page that is a child of the SwipeView. Without that line, drawer paints itself over the whole window and can be called with side gesture from any page of the swipe view. On the other hand, when it is a child of an items it draws only over that item.

    But, the problem comes with the side gestures when that item is hidden from the user (it is not currentItem of the SwipeView). In that case, as far as I can tell, the GUI thread (main one) freezes for indefinite time (other threads still work). The same happens if you try to change the currentIndex of the swipe view when the Drawer is shown (use TabBar buttons below).

    As a hot-fix I just disable (enabled: false) the whole page that contains the Drawer while it is out of the user view, and bound the Drawer's interactive property to the enabled property of the parent item.

    But is this an expected behavior or am I doing something wrong here? Why this happens? Maybe, if this is somehow goes against framework rules, it probably should show me some kind of an error message when attempting to do so?