Search code examples
javascriptqtqmlwidth

QML Navigation Bar isn't resizing


:) I'm currently reading book "End to End GUI Development with Qt5". To gain more knowledge how is everything is working I'm executing code from book with small changes done by me. Back to the point. Currently I have a problem with resizing of navigation bar when user is clicking toggle button (first button at navigation bar) at the top of navigation bar. *Window after running aplication

Starting view is done with usage of "MasterView.qml" file:

import QtQuick
import QtQuick.Window 2.15
import QtQuick.Controls 2.2
import assets 1.0
import components 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Client Management")

    NavigationBar {
        id: navigationBar
    }

    Connections {
        target: masterController.ui_navigationController
        onGoCreateClientView: contentFrame.replace("qrc:/views/CreateClientView.qml")
        onGoDashboardView:    contentFrame.replace("qrc:/views/DashboardView.qml")
        onGoEditClientView:   contentFrame.replace("qrc:/views/EditClientView.qml", {selectedClient: client})
        onGoFindClientView:   contentFrame.replace("qrc:/views/FindClientView.qml")
    }

    StackView {
        id: contentFrame
        anchors {
            top: parent.top
            bottom: parent.bottom
            left: navigationBar.right
            right: parent.right
        }
        clip: true
    }

    Component.onCompleted: contentFrame.replace("qrc:/views/DashboardView.qml");
}

Content of NavigationBar.qml component:

import QtQuick
import QtQuick.Controls 2.2
import assets 1.0

Item {
    property bool isCollapsed: true
    property color hoverColour: Style.colourNavigationBarBackground
    anchors {
        top: parent.top
        bottom: parent.bottom
        left: parent.left
        right: contentFrame.left
    }
    width: Style.widthNavigationBarCollapsed

    Rectangle {
        id: background
        anchors.fill: parent
        color: Style.colourNavigationBarBackground
        Column {
            NavigationButton {
                iconCharacter: "\uf0c9"
                description: ""
                hoverColour: "#993333"
                onNavigationButtonClicked: {
                    isCollapsed = !isCollapsed
                    console.log("Dashboard toggle")
                    console.log("Value of collapsed: " + isCollapsed)
                    if(isCollapsed) {
                        parent.width = Style.widthNavigationBarCollapsed
                    } else {
                        console.log("Width value before: " + parent.width)
                        parent.width  = Style.heightNavigationBarExpanded
                        console.log("Style heightNavigationBarExpanded " + Style.heightNavigationBarExpanded)
                        console.log("Width value after: " + parent.width)
                    }
                        console.log("Item Background width " + parent.width)
                }
            }
            NavigationButton {
                iconCharacter: "\uf015"
                description: "Dashboard"
                hoverColour: "#993333"
            }
            NavigationButton {
                iconCharacter: "\uf234"
                description: "New Client"
                hoverColour: "#993333"
            }
            NavigationButton {
                iconCharacter: "\uf002"
                description: "Find Client"
                hoverColour: "#993333"
            }
        }

        states: [
            State {
                name: "hover"
                PropertyChanges {
                    target: background
                    color: hoverColour
                }
            }

        ]

    }

}

With NavigationButton component having code like this:

import QtQuick
import QtQuick.Controls 2.2
import assets 1.0
Item  {
    property alias iconCharacter: textIcon.text
    property alias description: textDescription.text
    property color hoverColour: Style.colourNavigationBarBackground
    signal navigationButtonClicked()

    width: Style.widthNavigationButton
    height: Style.heightNavigationButton

    Rectangle {
        id: background
        anchors.fill: parent
        color: Style.colourNavigationBarBackground
        Row {
            Text {
                id: textIcon
                width: Style.widthNavigationButtonIcon
                height: Style.heightNavigationButtonIcon
                font {
                    family: Style.fontAwesome
                    pixelSize: Style.pixelSizeNavigationBarIcon
                }
                color: Style.colourNavigationBarFont
                text: "\uf0c9"
            }
            Text {
                id: textDescription
                width: Style.widthNavigationButtonDescription
                height: Style.heightNavigationButtonDescription
                color: Style.colourNavigationBarFont
                text: ""
            }
        }
        MouseArea {
            anchors.fill: parent
            cursorShape: Qt.PointingHandCursor
            hoverEnabled: true
            onEntered: background.state = "hover"
            onExited: background.state = ""
            onClicked: navigationButtonClicked()
        }
    }
}

Color and size properties are placed in another file "Style.qml":

pragma Singleton
import QtQuick 2.9

Item {
    property alias fontAwesome: fontAwesomeLoader.name
    readonly property color colourBackground: "#efefef"
    readonly property color colourNavigationBarBackground: "#000000"
    readonly property color colourNavigationBarFont: "#ffffff"
    readonly property int pixelSizeNavigationBarIcon: 42
    readonly property real widthNavigationButtonIcon: 80
    readonly property real heightNavigationButtonIcon: widthNavigationButtonIcon
    readonly property real widthNavigationButtonDescription: 240
    readonly property real heightNavigationButtonDescription: heightNavigationButtonIcon
    readonly property real widthNavigationButton: widthNavigationButtonIcon + widthNavigationButtonDescription
    readonly property real heightNavigationButton: Math.max(heightNavigationButtonIcon, heightNavigationButtonDescription)

    readonly property real widthNavigationBarCollapsed: widthNavigationButtonIcon
    readonly property real heightNavigationBarExpanded: 320
    FontLoader {
        id: fontAwesomeLoader
        source: "qrc:/assets/fontawesome.ttf"
    }
}

As I wrote earlier, there is problem erupting after clicking navigation button. The main purpose of it is to collapse / expand navigation bar (from width of 80 to 320).

onNavigationButtonClicked: {
                    isCollapsed = !isCollapsed
                    console.log("Dashboard toggle")
                    console.log("Value of collapsed: " + isCollapsed)
                    if(isCollapsed) {
                        parent.width = Style.widthNavigationBarCollapsed
                    } else {
                        console.log("Width value before: " + parent.width)
                        parent.width  = Style.heightNavigationBarExpanded
                        console.log("Style heightNavigationBarExpanded " + Style.heightNavigationBarExpanded)
                        console.log("Width value after: " + parent.width)
                    }
                        console.log("Item Background width " + parent.width)
                }

But... nothing is happening. Even tho in console I can see that when I click that first button values of parent.width (in that case of Item) are constantly changing. But my navigation bar isn't expanding in any case. Why is that happening?


Solution

  • So there are multiple issues with your design.

    1. You shouldn't anchor to all four sides top, left, right and bottom and expect setting width would impact the width of the fully anchored item. This is the case for the root object in NavigationBar.qml.
    2. In your onNavigationButtonClicked signal handler you set the parent.width to expand the navigation bar, but what you actually want is to set the width of the root item in NavigationBar. So what you need to do is to add an id to the root item Item of NavigationBar, e.g. id: root and in the signal handler set root.width = 320 and root.width = 80.

    Here is a quick demo

    import QtQuick
    import QtQuick.Window
    import QtQuick.Controls
    
    Window {
        id: root
        width: 640
        height: 480
        visible: true
        title: qsTr("Client Management")
    
        property int btnWidth: 80
        property int btnHeight: 80
    
        component NavigationButton : Rectangle {
            id: navigationButton
    
            property alias icon: text.text
    
            signal clicked
    
            width: root.btnWidth
            height: root.btnHeight
            border {
                color: "black"
                width: 1
            }
    
            Text {
                id: text
                anchors.centerIn: parent
                font.pixelSize: 32
            }
    
            MouseArea {
                id: mouseArea
                anchors.fill: parent
                hoverEnabled: true
                onClicked: navigationButton.clicked()
            }
    
            states: [
                State {
                    name: "idle"
                    when: !mouseArea.containsMouse
                    PropertyChanges {
                        target: navigationButton
                        color: "red"
                    }
                },
                State {
                    name: "hover"
                    when: mouseArea.containsMouse
                    PropertyChanges {
                        target: navigationButton
                        color: "blue"
                    }
                }
            ]
        }
    
        component NavigationBar : Rectangle {
            id: navigationBar
    
            property bool expanded: false
    
            width: root.btnWidth
            height: root.height
            color: "gray"
    
            Column {
    
                NavigationButton {
                    icon: navigationBar.expanded ? "X" : ">"
                    onClicked: navigationBar.expanded = !navigationBar.expanded
                }
    
                Repeater {
                    model: 3
    
                    NavigationButton { icon: modelData }
                }
            }
    
            states: [
                State {
                    name: "collapsed"
                    when: !navigationBar.expanded
                    PropertyChanges {
                        target: navigationBar
                        width: root.btnWidth
                    }
                },
                State {
                    name: "expanded"
                    when: navigationBar.expanded
                    PropertyChanges {
                        target: navigationBar
                        width: 320
                    }
                }
            ]
        }
    
        NavigationBar {}
    }