Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Dynamic height for card/rectangle used as ListView delegate
QtWS25 Last Chance

Dynamic height for card/rectangle used as ListView delegate

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
2 Posts 1 Posters 521 Views
  • 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.
  • O Offline
    O Offline
    ortonomy
    wrote on 10 Sept 2020, 11:26 last edited by
    #1

    Hi, long-time web dev here, building a native app for desktop for the first time on QT/QT Creator. Been learning QT/QML for a day, and I've got this far, but I need help.

    I'm building an a fairly simple interface to my design, where in I have a list view whose delegate is a custom component which in itself is a card that display a bunch of information about a gitlab issue. This issue (its text and content are completely dynamic)

    Here is an example a card. Every part marked with a red square can have a variable height either due to:

    1. text length
    2. tab content varying in height: (i.e. list tab is just a set of icons, assignee is a set of assignees and labels, and estimate is a simple number entry

    task card

    The problem I've having is the layout of the cards. I'm trying to use the RoyLayout and ColumnLayout types, because I know they have their own intrinsic heights calculated from children. This is important to me, because, and this is really important I don't want to have to specify explicit heights for any of the content. I want the cards to be as compact as possible and grow with their content, including the internal card menu, which is only visible if the card is selected.

    I'm almost there, but I just can't quite get some of the margins correct (especially on the bottom margin) which seems to be be flush against the bottom of the card, and in fact, despite being invisible, seems to be reserving space for the hidden buttons:

    ListView

    ColumnLayout {
        id: taskList
        Layout.fillWidth: true
        Layout.fillHeight: true
        spacing: 0
    
        ListView {
            id: taskListView
            Layout.fillHeight: true
            Layout.fillWidth: true
            orientation: Qt.Vertical
            spacing: 10
    
            model: ListModel {
                id: listModel
                Component.onCompleted: {
                    for (var i = 0; i < 20; i++)
                    listModel.append({"Name": "Item " + i})
                    taskListView.currentIndex = -1
                }
            }
    
            delegate: TaskCard {
                margin: 12
                cardIndex: index
                isSelected: taskListView.currentIndex == index
                onSelected: {
                    taskListView.currentIndex = index
                }
            }
    
            focus: true
            clip: true
        }
    }
    
    

    TaskCard

    Item {
        id: taskCard
    
        // data props
        property int cardIndex
        property int taskId
        property string name: "[EXAMPLE] Do something great today."
        property string reference: "aliengen/aProject#1"
        property var assignee: {
            assignee_id: 1
            name: 'Example guy'
        }
        property string stage: "To Do"
        property real estimate: 0
        property real elapsed: 0
        property bool shouldShowAssignee: false
        property bool isSelected: false
        property int selectedMenuType: 1
    
        // layout props
        property real margin: 12
    
        height: taskCardContent.childrenRect.height
        anchors {
            left: parent.left
            right: parent.right
        }
    
    
        // signals
        signal selected(int id)
    
        // states
        states: [
            State {
                name: 'SELECTED'
                when: taskCard.isSelected
            }
        ]
    
    
    
    
        Rectangle {
            id: taskCardContent
            anchors {
                fill: parent
                leftMargin: taskCard.margin
                rightMargin: taskCard.margin
            }
    
            height: taskCardContent.childrenRect.height
    
    
            color: styles.c_secondary
            border {
                width: taskCard.state == 'SELECTED' ? 1 : 0
                color: styles.c_ag_green
            }
    
            MouseArea {
               onClicked: taskCard.selected(taskCard.cardIndex)
               anchors.fill: parent
            }
    
    
            ColumnLayout {
               id: taskCardContentLayout
               anchors {
                   left: parent.left
                   right: parent.right
                   leftMargin: 16
                   rightMargin: 16
               }
    
    
    
               RowLayout {
                   id: taskCardMetaLayout
                   Layout.fillWidth: true
    
    
                   Label {
                      text: taskCard.stage
                      font.pixelSize: styles.f_xs
                      font.weight: Font.Medium
                      color: styles.c_ag_green
                      Layout.fillWidth: true
                      Layout.alignment: Qt.AlignLeft
                   }
    
                   Rectangle {
                       id: taskCardTimingLayout
                       Layout.alignment: Qt.AlignRight
                       Layout.fillWidth: true
                       height: taskCardTimingLayout.childrenRect.height
                       color: styles.c_secondary
    
                       Label {
                          id: taskCardTimingEstimate
                          text: taskCard.estimate + "h / "
                          font.pixelSize: styles.f_xs
                          font.weight: Font.Normal
                          color: styles.c_ag_green
                          anchors {
                              right: taskCardTimingRemaining.left
                          }
                       }
    
                       Label {
                          id: taskCardTimingRemaining
                          text: taskCard.elapsed + "h"
                          font.pixelSize: styles.f_xs
                          font.weight: Font.Normal
                          color: styles.c_ag_blue
                          anchors {
                              right: parent.right
                          }
                       }
    
                   }
    
    
    
    
               }
    
               RowLayout {
                   id: taskTitleRowLayout
                   Layout.fillWidth: true
    
                   Label {
                       id: taskCardName
                       text: taskCard.name
                       color: styles.c_primary
                       minimumPixelSize: styles.f_m
                       font.pixelSize: styles.f_m
                       font.weight: Font.Bold
                       wrapMode: Text.WordWrap
                       Layout.fillWidth: true
                       Layout.alignment: Qt.AlignLeft
                   }
    
                   Button {
                       width: 40
                       Layout.alignment: Qt.AlignRight
                       id: taskCardTimerButton
                       background: Rectangle {
                           color: 'transparent'
                       }
                       icon.source: './images/IconPlayOutline.svg'
                       icon.name: 'IconPlayOutline'
                       icon.color: styles.c_ag_green
                   }
               }
    
               RowLayout {
                   id: taskCardReferenceLayout
                   Layout.fillWidth: true
    
                   Label {
                      id: taskCardReference
                      text: taskCard.reference
                      font.pixelSize: styles.f_s
                      font.weight: Font.Medium
                      color: styles.c_accent_1
                      wrapMode: Text.WordWrap
                      Layout.fillWidth: true
                   }
               }
    
    
               RowLayout {
                   visible: taskCard.isSelected
                   id: taskCardControlMenuLayout
                   Layout.fillWidth: true
    
                   ColumnLayout {
                       id: taskCardControlMenuInnerLayout
                       Layout.fillWidth: true
    
                       RowLayout {
                           id: taskCardControlMenuTabs
                           Layout.fillWidth: true
                           spacing: 0
    
                           Button {
                               id: taskCardControlMenuTabListChooser
                               Layout.fillWidth: true
                               Layout.preferredHeight: 20
                               background: Rectangle {
                                   color: styles.c_secondary
                               }
                               contentItem: Text {
                                   text:  qsTr("LIST")
                                   color: selectedMenuType == 1 ? styles.c_ag_green : styles.c_accent_1
                                   font.pixelSize: styles.f_s
                                   font.weight: selectedMenuType == 1 ? Font.Bold : Font.Normal
                                   horizontalAlignment: Text.AlignHCenter
                                   verticalAlignment: Text.AlignVCenter
                               }
                           }
    
                           Button {
                               id: taskCardControlMenuTabAssigneeChooser
                               Layout.fillWidth: true
                               Layout.preferredHeight: 20
                               background: Rectangle {
                                   color: styles.c_secondary
                               }
                               contentItem: Text {
                                   text:  qsTr("ASSIGNMENT")
                                   color: selectedMenuType == 2 ? styles.c_ag_green : styles.c_accent_1
                                   font.pixelSize: styles.f_s
                                   font.weight: selectedMenuType == 2 ? Font.Bold : Font.Normal
                                   horizontalAlignment: Text.AlignHCenter
                                   verticalAlignment: Text.AlignVCenter
                               }
                           }
    
                           Button {
                               id: taskCardControlMenuTabEstimateProvider
                               Layout.fillWidth: true
                               Layout.preferredHeight: 20
                               background: Rectangle {
                                   color: styles.c_secondary
                               }
                               contentItem: Text {
                                   text:  qsTr("ESTIMATE")
                                   color: selectedMenuType == 3 ? styles.c_ag_green : styles.c_accent_1
                                   font.pixelSize: styles.f_s
                                   font.weight: selectedMenuType == 3 ? Font.Bold : Font.Normal
                                   horizontalAlignment: Text.AlignHCenter
                                   verticalAlignment: Text.AlignVCenter
                               }
                           }
                       }
                   }
               }
    
    
            }
    
    
        }
    

    Resulting render:

    How can I fix these things?

    1. There is too much space on the bottom side of the card
    2. The buttons overflow the box, and the border
    3. there is no padding on the box on the top side

    rendered cards

    Any help would be appreciated

    1 Reply Last reply
    0
    • O Offline
      O Offline
      ortonomy
      wrote on 11 Sept 2020, 10:42 last edited by
      #2

      real task card

      Solved it for those who care. Had to jump through some hoops:

      Task Card

      Item {
          id: taskCard
      
          // data props
          property int cardIndex
          property int taskId
          property string name: "[EXAMPLE] Do something great today."
          property string reference: "aliengen/aProject#1"
          property var assignee: {
              assignee_id: 1
              name: 'Example guy'
          }
          property string listType: 'BACKLOG'
          property string stage: "To Do"
          property real estimate: 0
          property real elapsed: 0
          property bool shouldShowAssignee: false
          property bool isSelected: false
          property int selectedMenuType: 1
      
      
          // layout props
          property real margin: 12
      
          anchors {
              left: parent.left
              right: parent.right
          }
          height: taskCard.childrenRect.height
      
      
          // signals
          signal selected(int id)
      
          // states
          states: [
              State {
                  name: 'SELECTED'
                  when: taskCard.isSelected
              }
          ]
      
      
      
      
          Rectangle {
              id: taskCardContent
              anchors {
                  left: parent.left
                  right: parent.right
                  leftMargin: taskCard.margin
                  rightMargin: taskCard.margin
              }
      
              height: taskCardContentLayout.height
      
              color: styles.c_secondary
              border {
                  width: taskCard.state == 'SELECTED' ? 1 : 0
                  color: styles.c_ag_green
              }
      
      
      
      
              MouseArea {
                 onClicked: taskCard.selected(taskCard.cardIndex)
                 anchors.fill: parent
              }
      
      
              Rectangle {
                  id: taskCardInnerSpacer
                  height: taskCardContentLayout.height - 2
                  anchors {
                      left: parent.left
                      right: parent.right
                      leftMargin: 16
                      rightMargin: 16
                      topMargin: 12
                      bottomMargin: 12
                  }
                  color: styles.c_secondary
                  y: 1
      
      
                  ColumnLayout {
                     id: taskCardContentLayout
                     anchors {
                         left: parent.left
                         right: parent.right
                     }
      
                     RowLayout {
                         id: taskCardMetaLayout
                         Layout.fillWidth: true
                         Layout.topMargin: 16
                         spacing: 0
      
      
                         Label {
                            text: taskCard.stage
                            font.pixelSize: styles.f_xs
                            font.weight: Font.Medium
                            color: styles.c_ag_green
                            Layout.fillWidth: true
                            Layout.alignment: Qt.AlignLeft
                         }
      
                         Rectangle {
                             id: taskCardTimingLayout
                             Layout.alignment: Qt.AlignRight
                             Layout.fillWidth: true
                             height: taskCardTimingLayout.childrenRect.height
                             color: styles.c_secondary
      
                             Label {
                                id: taskCardTimingEstimate
                                text: taskCard.estimate + "h / "
                                font.pixelSize: styles.f_xs
                                font.weight: Font.Normal
                                color: styles.c_ag_green
                                anchors {
                                    right: taskCardTimingRemaining.left
                                }
                             }
      
                             Label {
                                id: taskCardTimingRemaining
                                text: taskCard.elapsed + "h"
                                font.pixelSize: styles.f_xs
                                font.weight: Font.Normal
                                color: styles.c_ag_blue
                                anchors {
                                    right: parent.right
                                }
                             }
      
                         }
      
      
      
      
                     }
      
                     RowLayout {
                         id: taskTitleRowLayout
                         Layout.fillWidth: true
                         spacing: 0
      
                         Label {
                             id: taskCardName
                             text: taskCard.name
                             color: styles.c_primary
                             minimumPixelSize: styles.f_m
                             font.pixelSize: styles.f_m
                             font.weight: Font.Bold
                             wrapMode: Text.WordWrap
                             Layout.fillWidth: true
                             Layout.alignment: Qt.AlignLeft
                         }
      
                         Button {
                             width: 40
                             Layout.alignment: Qt.AlignRight
                             id: taskCardTimerButton
                             background: Rectangle {
                                 color: 'transparent'
                             }
                             icon.source: './images/IconPlayOutline.svg'
                             icon.name: 'IconPlayOutline'
                             icon.color: styles.c_ag_green
                         }
                     }
      
                     RowLayout {
                         id: taskCardReferenceLayout
                         Layout.fillWidth: true
                         Layout.bottomMargin: taskCard.isSelected ? 0 : 16
                         spacing: 0
      
                         Label {
                            id: taskCardReference
                            text: taskCard.reference
                            font.pixelSize: styles.f_s
                            font.weight: Font.Medium
                            color: styles.c_accent_1
                            wrapMode: Text.WordWrap
                            Layout.fillWidth: true
                         }
                     }
      
      
      
                     RowLayout {
                         id: taskCardControlsLayout
                         Layout.fillWidth: true
                         Layout.bottomMargin: taskCard.isSelected ? 16 : 0
                         spacing: 0
                         visible: taskCard.isSelected
      
                         ColumnLayout {
                             id: taskCardControlMenuInnerLayout
                             Layout.fillWidth: true
                             spacing: 0
      
                             RowLayout {
                                 id: taskCardControlMenuTabs
                                 Layout.fillWidth: true
                                 spacing: 0
      
      
                                 Button {
                                     id: taskCardControlMenuTabListChooser
                                     Layout.fillWidth: true
                                     Layout.preferredHeight: 20
                                     background: Rectangle {
                                         color: styles.c_secondary
                                     }
                                     contentItem: Text {
                                         text:  qsTr("LIST")
                                         color: selectedMenuType == 1 ? styles.c_ag_green : styles.c_accent_1
                                         font.pixelSize: styles.f_s
                                         font.weight: selectedMenuType == 1 ? Font.Bold : Font.Normal
                                         horizontalAlignment: Text.AlignHCenter
                                         verticalAlignment: Text.AlignVCenter
                                     }
                                     onClicked: selectedMenuType = 1
                                 }
      
                                 Button {
                                     id: taskCardControlMenuTabAssigneeChooser
                                     Layout.fillWidth: true
                                     Layout.preferredHeight: 20
                                     background: Rectangle {
                                         color: styles.c_secondary
                                     }
                                     contentItem: Text {
                                         text:  qsTr("ASSIGNMENT")
                                         color: selectedMenuType == 2 ? styles.c_ag_green : styles.c_accent_1
                                         font.pixelSize: styles.f_s
                                         font.weight: selectedMenuType == 2 ? Font.Bold : Font.Normal
                                         horizontalAlignment: Text.AlignHCenter
                                         verticalAlignment: Text.AlignVCenter
                                     }
                                     onClicked: selectedMenuType = 2
                                 }
      
                                 Button {
                                     id: taskCardControlMenuTabEstimateProvider
                                     Layout.fillWidth: true
                                     Layout.preferredHeight: 20
                                     background: Rectangle {
                                         color: styles.c_secondary
                                     }
                                     contentItem: Text {
                                         text:  qsTr("ESTIMATE")
                                         color: selectedMenuType == 3 ? styles.c_ag_green : styles.c_accent_1
                                         font.pixelSize: styles.f_s
                                         font.weight: selectedMenuType == 3 ? Font.Bold : Font.Normal
                                         horizontalAlignment: Text.AlignHCenter
                                         verticalAlignment: Text.AlignVCenter
                                     }
                                     onClicked: selectedMenuType = 3
                                 }
                             }
      
                             RowLayout {
                                 id: taskControlsControlContainer
                                 Layout.fillWidth: true
                                 spacing: 0
      
                                 Rectangle {
                                      id: taskCardControlsListChooser
                                      visible: selectedMenuType == 1
                                      Layout.fillWidth: true
                                      height: taskCardControlsListChooserLayout.height
                                      color: styles.c_secondary
                                      anchors.margins: 4
      
                                      RowLayout {
                                          id: taskCardControlsListChooserLayout
                                          anchors.left: parent.left
                                          anchors.right: parent.right
                                          spacing: 0
      
                                          Button {
                                              icon.height: 14
                                              icon.width: 14
                                              icon.source: './images/IconBacklog.svg'
                                              icon.name: 'IconBacklog'
                                              icon.color: taskCard.listType == 'BACKLOG' ? styles.c_ag_green : styles.c_accent_1
                                              onClicked: taskCard.listType = 'BACKLOG'
                                              background: Rectangle {
                                                  color: styles.c_secondary
                                                  anchors.fill: parent
                                              }
                                              Layout.fillWidth: true
      
                                          }
                                          Button {
                                              icon.height: 14
                                              icon.width: 14
                                              icon.source: './images/IconPlay.svg'
                                              icon.name: 'IconThisWeek'
                                              icon.color: taskCard.listType == 'THIS' ? styles.c_ag_green : styles.c_accent_1
                                              onClicked: taskCard.listType = 'THIS'
                                              background: Rectangle {
                                                  color: styles.c_secondary
                                                  anchors.fill: parent
                                              }
                                              Layout.fillWidth: true
      
                                          }
                                          Button {
                                              icon.height: 14
                                              icon.width: 14
                                              icon.source: './images/IconNext.svg'
                                              icon.name: 'IconNextWeek'
                                              icon.color: taskCard.listType == 'NEXT' ? styles.c_ag_green : styles.c_accent_1
                                              onClicked: taskCard.listType = 'NEXT'
                                              background: Rectangle {
                                                  color: styles.c_secondary
                                                  anchors.fill: parent
                                              }
                                              Layout.fillWidth: true
                                          }
                                          Button {
                                              icon.height: 14
                                              icon.width: 14
                                              icon.source: './images/IconSnooze.svg'
                                              icon.name: 'IconLater'
                                              icon.color: taskCard.listType == 'LATER' ? styles.c_ag_green : styles.c_accent_1
                                              onClicked: taskCard.listType = 'LATER'
                                              background: Rectangle {
                                                  color: styles.c_secondary
                                                  anchors.fill: parent
                                              }
                                              Layout.fillWidth: true
                                          }
                                      }
                                 }
      
                                 Rectangle {
                                      id: taskCardControlsAssigneesChooser
                                      visible: selectedMenuType == 2
                                 }
      
                                 Rectangle {
                                      id: taskCardControlsEstimateProvider
                                      visible: selectedMenuType == 3
                                 }
                             }
                         }
                     }
      
      
      
      
                  }
      
      
              }
          }
      
      
      
      
      
      
      }
      
      1 Reply Last reply
      1

      1/2

      10 Sept 2020, 11:26

      • Login

      • Login or register to search.
      1 out of 2
      • First post
        1/2
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved