1

I have to create some "tabs" in QML which should have rounded corners at the top and a border all over it :

enter image description here

I managed to create the rounded rectangle by using 2 rectangles :

(the tabs are part of a listview)

 ListView {
    id: listView
    anchors.fill: parent
    orientation: ListView.Horizontal
    spacing: Math.floor(0.60 * parent.width / 100)

    model: TabsModel{}

    delegate: TabsDelegate {

        height: parent.height

    }
}

The delegate which is the actual tab :

Item {
    id: root

    width: 200

    Rectangle {
        id: topRect
        anchors.fill: parent
        radius: 5
        color: backgroundColor
        /*border.width: 1
        border.color: borderColor*/
    }

   Rectangle {
        id: bottomRect
        anchors.bottom: parent.bottom
        anchors.left: topRect.left
        anchors.right: topRect.right
        height: 1 / 2 * parent.height
        color: backgroundColor
        /*border.width: 1
        border.color: borderColor*/
    }

    Text {
        id: text
        anchors.verticalCenter: parent.verticalCenter
        anchors.left: parent.left
        anchors.leftMargin: spaceBefore
        text: label
        color: textColor
    }
}

With this code i have the following result :

enter image description here

Obviously if i add the borders , i end up with with a border in the middle of my tabs : enter image description here

Any ideas how i can manage to get what i want in qml ?

grunk
  • 14,718
  • 15
  • 67
  • 108

3 Answers3

3

You can simply add another Rectangle (between bottomRect and text) to hide the middle border:

Rectangle {
    anchors {
        fill: bottomRect
        leftMargin: bottomRect.border.width
        bottomMargin: bottomRect.border.width
        rightMargin: bottomRect.border.width
    }
    color: backgroundColor
}
augre
  • 2,011
  • 12
  • 18
1

You could use a single rectangle if you can get away with tucking its bottom edge under something on the GUI. That's about all you can do out of the box as QML doesn't support custom corner angling. Granted, you can try covering that line up with yet another third rectangle, but that's clearly the wrong and messy approach you shouldn't be taking.

Otherwise you will have to do manual painting.

There is a number of options here.:

1 - use Canvas to draw from QML, and use that graphic with a BorderImage, which will allow you to use the same, single time painted elements to drive an arbitrary size label. You can also use an image generated by a 3rd party program, but drawing it in QML is more flexible

2 - use QQuickPaintedItem and draw the entire tab with C++ and QPainter

3 - implement a proper QQuickItem that generates the needed geometry and renders the item efficiently with the QML scene graph in OpenGL.

dtech
  • 47,916
  • 17
  • 112
  • 190
  • For the third Rectangle: messy option yes, but why wrong? It's always how I did it since it's the easiest way to deal with different radius for the corners (even if it's indeed annoying). – augre Jun 01 '18 at 13:53
  • Because instead of getting one clean item you make a mess of two item, covered by yet another item. 3 objects is more than 1, and 1 is all you really need. Those objects consume system resources and add needless complexity. Doing things wrong and then even more things wrong to cover it up is not a sound strategy in software engineering. – dtech Jun 01 '18 at 14:03
  • Hiding the bottom part is not really an option because i need the bottom border. I managed to to it with 2 rectangles. The top rectangle go under an other part of the ui as you suggested while the bottom rectangle is set to 1px heigt to draw the bottom border. – grunk Jun 01 '18 at 14:27
  • @dtech Would any of the other options be much less resource consuming? For example I tried to search a bit and found [here](https://stackoverflow.com/a/29196812/4503757) another of your answers about a rounded `Rectangle` created with a `QPainter`. Don't you need to add several rectangles to the path to differenciate the borders (as also done in [this answer](https://stackoverflow.com/a/15289912/4503757))? Wouldn't it take the same amount of resources as using 3 Rectangles in QML? I am not really familiar with drawing with `QPainter` so I would be interested to have your opinion on it. – augre Jun 01 '18 at 14:32
  • From my answer, 1 is the best compromise between complexity and efficiency, because it only draws once and then reuses the pixel data to stretch it as required. 2 is the "half assed solution" really, and 3 is the most efficient, albeit the most complex. Also, in 1 you can also use shaders to colorize the result in any desired color and still use only one source image for the stencil. – dtech Jun 04 '18 at 21:59
0

I have recently needed a rounded rectangle with different radius in each corner and with border, so I implemented one. It depends on Qt 6 and uses shaders so it doesn't work with software rendering, still I hope it helps some people. The code is available at https://gitlab.com/Akeras/QmlRoundedRectangle

Andras
  • 14
  • 4
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 13 '22 at 20:22