Columns of grouped checked boxes overlapping with one another

Viewed 42

So, I'm trying to create a filter box for an ecommerce-based application that I'm working on and I want to make multiple button groups of check boxes within columns. I tried to separate the different columns but they overlap with one another. For example, the priceColumn overlaps with the conditionColumn. I am looking for a way to separate each button group by line. Is there anyway around this or any other solution that you would suggest? I'm new to QML by the way.

Here's my code for example:

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12

import "." as NeroshopComponents

Pane {
    id: filterBox
    clip: true // The area in which the contents of the filterBox will be bounded to (set width and height) // If clip is false then the contents will go beyond/outside of the filterBox's bounds
    width: 250; height: 540
    background: Rectangle { 
        color: (NeroshopComponents.Style.darkTheme) ? "#2e2e2e"/*"#121212"*/ : "#a0a0a0"
        radius: 3
    }    
    // conditionGroup
    ButtonGroup {
        id: conditionButtonGroup
        buttons: conditionColumn.children
        exclusive: false // more than one button in the group can be checked at any given time
        checkState: conditionParentBox.checkState
        onClicked: {
            console.log("Selected condition:", button.text)
            if(checkState == Qt.Unchecked) {
                console.log("checkState: NO button is checked")
            }
            if(checkState == Qt.Checked) {
                console.log("checkState: All buttons are checked")
            }            
            if(checkState == Qt.PartiallyChecked) {
                console.log("checkState: One or more buttons are checked")
            }
        }
    }
    // priceGroup
    ButtonGroup {
        id: priceButtonGroup
        buttons: priceColumn.children
        exclusive: false // more than one button in the group can be checked at any given time
        checkState: priceParentBox.checkState
        onClicked: {
            console.log("Selected price range:", button.text)
            if(checkState == Qt.Unchecked) {
                console.log("checkState: NO button is checked")
            }
            if(checkState == Qt.Checked) {
                console.log("checkState: All buttons are checked")
            }            
            if(checkState == Qt.PartiallyChecked) {
                console.log("checkState: One or more buttons are checked")
            }
        }
    }        
    ////////////////////
    Rectangle {
        id: filterOptions
        //anchors.fill: parent
            x: -horizontalScrollBar.position * width
            y: -verticalScrollBar.position * height        
            color: "transparent"
            width: parent.width
            height: parent.height
        Column {//ColumnLayout {
            id: conditionColumn
            
            Text { 
                text: qsTr("Condition"); 
                font.bold: true
                color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
            }
            CheckBox {
                id: conditionParentBox
                //text: qsTr("Any")//qsTr("Parent")
                checkState: conditionButtonGroup.checkState
                
                Text {
                    text: qsTr("Any")
                    color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
                    anchors.left: parent.right
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: (parent.height - this.contentHeight) / 2
                }                
            }        
            CheckBox { 
                //checked: false
                //text: qsTr("New")
                leftPadding: indicator.width
                ButtonGroup.group: conditionButtonGroup
                Text {
                    text: qsTr("New")
                    color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
                    anchors.left: parent.right
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: (parent.height - this.contentHeight) / 2
                }                      
            }
            CheckBox { 
                //text: qsTr("Used")
                leftPadding: indicator.width
                ButtonGroup.group: conditionButtonGroup
                Text {
                    text: qsTr("Used")
                    color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
                    anchors.left: parent.right
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: (parent.height - this.contentHeight) / 2
                }                      
            }
            CheckBox { 
                //text: qsTr("Refurbished/Renewed")
                leftPadding: indicator.width
                ButtonGroup.group: conditionButtonGroup
                Text {
                    text: qsTr("Refurbished/Renewed")
                    color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
                    anchors.left: parent.right
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: (parent.height - this.contentHeight) / 2
                }                      
            }
        }
        ////////////////////////
        Column {//ColumnLayout {
            id: priceColumn
            Text { 
                text: qsTr("Price")
                font.bold: true
                color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
            }
            CheckBox { 
                id: priceParentBox
                checkState: priceButtonGroup.checkState
                Text {
                    text: qsTr("Any")
                    color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
                    anchors.left: parent.right
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: (parent.height - this.contentHeight) / 2
                }                
            }
            CheckBox { 
                leftPadding: indicator.width
                ButtonGroup.group: priceButtonGroup       
                Text {
                    text: qsTr("$0.00-$1.00")
                    color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
                    anchors.left: parent.right
                    anchors.leftMargin: 0
                    anchors.top: parent.top
                    anchors.topMargin: (parent.height - this.contentHeight) / 2
                }                       
            }
        }        
        } // Rectangle: filterOptions
        ScrollBar {
            id: verticalScrollBar
            hoverEnabled: true
            active: hovered || pressed
            orientation: Qt.Vertical
            size: (filterBox.height - 20) / filterOptions.height//filterBox.background.height / conditionColumn.height // 20 is the bottomMargin I guess?
            anchors.top: parent.top
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            policy: ScrollBar.AlwaysOn
        }

        ScrollBar {
            id: horizontalScrollBar
            hoverEnabled: true
            active: hovered || pressed
            orientation: Qt.Horizontal
            size: filterBox.background.width / filterOptions.width
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            policy: ScrollBar.AsNeeded
        }
        // todo: sort by category, price, ratings, brand, color, etc.
}
1 Answers

I replaced your anchoring with ColumnLayout. I replaced Rectangle for Frame has an automatic border and padding effect. I replaced CheckBox for RadioButton, since, for exclusivity per group since your UI implied that use case. Qt QML automatically figures out how to deal with the two RadioButton groups since they fall in their own Frame/ColumnLayout so we needn't explicitly define a ButtonGroup. I replaced your ScrollBar implementation with ScrollBar.vertical

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Page {
    anchors.fill: parent
    Flickable {
        id: flickable
        anchors.fill: parent
        contentWidth: columnLayout.width
        contentHeight: columnLayout.height
        clip: true
        ColumnLayout {
            id: columnLayout
            width: flickable.width - 20
            Frame {
                Layout.fillWidth: true
                ColumnLayout {
                    width: parent.width
                    Label { text: qsTr("Condition") }
                    RadioButton { id: cond1; text: qsTr("Any") }
                    RadioButton { id: cond2; text: qsTr("New") }
                    RadioButton { id: cond3; text: qsTr("Used") }
                    RadioButton { id: cond4; text: qsTr("Refurbished/Renew") }
                    Text {
                        text:      (cond1.checked && cond1.text)
                                || (cond2.checked && cond2.text)
                                || (cond3.checked && cond3.text)
                                || (cond4.checked && cond4.text)
                                || qsTr("Nothing Selected")
                    }
                }
            }
            Frame {
                Layout.fillWidth: true
                ColumnLayout {
                    width: parent.width
                    Label { text: qsTr("Price") }
                    RadioButton { id: price1; text: qsTr("Any") }
                    RadioButton { id: price2; text: qsTr("$0.00-$1.00") }
                    Text {
                        text:      (price1.checked && price1.text)
                                || (price2.checked && price2.text)
                                || qsTr("Nothing Selected")
                    }

                }
            }
        }
        ScrollBar.vertical: ScrollBar {
            width: 20
            policy: ScrollBar.AlwaysOn
        }
    }
}

animate-gif

Related