5
votes

Summary: How can I stick an icon next to text, without hardcoding dimensions, and wrap the both of them in a MouseArea...in a way that works inside a GridLayout?


I have created a QML layout that has rows of labels across from tappable "buttons". The buttons are an icon along with text:

Two rows with two columns; the rightmost column has images and text inline

To create the buttons I am using a Row, so that the two items stick together properly (without any hardcoded dimensions) and have an automatic size that the GridLayout can use:

GridLayout {
  columns:2; rowSpacing:30

  Text {
    text: audioServer.label
    Layout.alignment: Qt.AlignLeft
  }

  Row {
    spacing:10; Layout.alignment:Qt.AlignRight
    Image { width:29; height:30; y:10; source:"qrc:/rescan.png" }
    Text  { text:"Find Another" }
  }

  Text {
    text: "System uptime "+system.uptime
    Layout.alignment: Qt.AlignLeft
  }

  Row {
    spacing:10; Layout.alignment:Qt.AlignRight
    Image { width:29; height:30; y:10; source:"qrc:/restart.png" }
    Text  { text: "Restart" }
  }
}

I want to put a MouseArea around each button. If I put it inside a row, like this...

Row {
  Image { width:29; height:30; y:10; source:"qrc:/rescan.png" }
  Text  { text:"Find Another" }

  MouseArea {
    anchors.fill: parent
    onClicked: rescan()
  }
}

...then I get the (reasonable) error QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function. And, more importantly, the layout breaks (I think the Row gets zero width, so the GridLayout has it flow off the right side.)

I cannot move the MouseArea outside of the GridLayout like this...

GridLayout {
  ...
  Row {
    id: rescanButton
    Image { width:29; height:30; y:10; source:"qrc:/rescan.png" }
    Text  { text:"Find Another" }
  }
}
MouseArea {
  anchors.fill: rescanButton
  onClicked: rescan()
}

...because you can only anchor to siblings or parents.

But I cannot put the MouseArea inside the GridLayout, because then it will try to lay it out as an item.

How can I get a MouseArea wrapping the buttons?

It's acceptable to me to use a container other than Row, but I strongly prefer not to hard-code any text or container dimensions.

1
Why don't you just make the MouseArea a child of the Image?Filip Hazubski
A terrible hack is that you can put the MouseArea as a child of the GridLayout; it will leave a blank cell for it, but using anchors.fill:myButton will cause the tap region to properly be around the button. You just have to put all the MouseArea at the beginning or end of the GridLayout, so that they don't leave holes in the middle.Phrogz
@FilipHazubski Because I want the user to be able to tap anywhere on the image or the text that goes with it. The "rescan.png" is just the circled arrows, but the user should also be able to tap on "Find Another" and have it work.Phrogz
You can make MouseArea a child of an Image but make its width equal Image.width + Text.width + gapWidth. :) I think you can define id property of Image and Text and it will be available only in the scope of the Row so MouseArea can use it.Filip Hazubski
Also (sorry for spamming but) you can make only MouseArea the child of the Row, make Text and Image children of the MouseArea and set its size according to children size.Filip Hazubski

1 Answers

9
votes

With your help we have got this:

GridLayout {
  ...
  MouseArea {
    onClicked: rescan()
    width:  childrenRect.width
    height: childrenRect.height
    Row {
      Image { width:29; height:30; y:10; source:"qrc:/rescan.png" }
      Text  { text:"Find Another" }
    }
  }
}