-1

I have the progressbar and i used Qt StyleSheet for rounding his corners. the problem is that when the indicator has not reached the 20% mark, it is not rounded on one side.

I attached screenshots to make it clearer.

I guess it has to do with my Qt StyleSheet.

u"QProgressBar:horizontal 
{\n
    border-radius: 15px;\n
    background: white;\n
}\n"
"QProgressBar::chunk:horizontal 
{\n
    background-color: #7A859B;\n
    border-radius :15px;\n
}\n"

enter image description here

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
D3-one 6
  • 45
  • 5
  • The problem is not on the percentage, but on the size of the chunk based on the radius. The same happens if the height of the progress bar is less than the diameter: whenever the chunk has a size (height **or** width) smaller than the double of the radius, it doesn't draw an ellypse anymore. I believe that it's due to the fact that the constructed object is actually a QPainterPath with two arcs connected, and the radius must be equal or smaller than the available space, otherwise the fill rule draws in the opposite direction. I'm afraid that there's no direct solution using stylesheets only – musicamante Jan 10 '21 at 19:13

1 Answers1

1

The issue is that setting a border radius to a rectangle that has a size smaller than the sum of the border radii (for normal case, the diameter), the painter path used to draw the frame becomes a rectangle, due to the way arcs are drawn.

Unfortunately there is no direct solution using stylesheets, and the only option I can think of is to subclass and override the paintEvent, then "trick" the style making it think that the current value is higher than what in reality is.

In the following example, I'm computing the minimum width required for the small value (I'm assuming 0), then evaluate the possible size of the bar based on the current value, and then compute the new "virtual" value based on the possible size above.

In this way, the minimum will always be a circle, and it will increase its width accordingly.

some examples at different values

class Progress(QtWidgets.QProgressBar):
    def paintEvent(self, event):
        qp = QtWidgets.QStylePainter(self)
        opt = QtWidgets.QStyleOptionProgressBar()
        self.initStyleOption(opt)
        rect = self.style().subElementRect(QtWidgets.QStyle.SE_ProgressBarContents, opt, self)
        minSize = rect.height()
        grooveSize = rect.width() - minSize - 1
        valueRange = self.maximum() - self.minimum()
        offset = self.value() / valueRange * grooveSize
        newValue = (minSize + 1 + offset) / rect.width() * valueRange
        if int(newValue) != newValue:
            newValue = min(self.maximum(), newValue + 1)
        opt.progress = newValue
        qp.drawControl(QtWidgets.QStyle.CE_ProgressBar, opt)

Do note that this is a very simple implementation that doesn't check if the range is valid, and doesn't consider the orientation nor the inverted position. In some cases it might appear a small rectangle depending on the size (I might have misplaced a 1 pixel difference somewhere).

musicamante
  • 41,230
  • 6
  • 33
  • 58