PDA

View Full Version : PixelMetric for QProgressBar gutter/margin spacing?



cmb
1st March 2014, 16:58
I have a subclass of QProgressBar that draws its own progress bar groove and contents by overriding paintEvent(), but I've noticed that the height of the bar is apparently supposed to change depending on the graphical theme in use at the time. For example, it looks fine when I test in Linux, but note the difference in height between the top bar and the bottom bars in this Windows Classic theme screenshot:

http://alum.wpi.edu/~colinb/images/qprogressbar_subclass.png

The top is the native QProgressBar. I want to duplicate that appearance. How do I get the correct vertical "gutter" spacing for the active style so that I can draw the bar at the correct distance from the borders of the groove?

EDIT: I think what I'm looking for is a PixelMetric from the active style, but I'm not sure which one. The only one that seems to be specific to progress bars is QStyle::PM_ProgressBarChunkWidth, but that's obviously not what I need. Any ideas?

--Colin

anda_skoa
1st March 2014, 20:22
All widgets call into the current QStyle's API to delegate each part of the drawing.
My suggestion is to look at the code of QProgressBar and see which methods it calls with which arguments and then repeat all those that you want not to change.

Cheers,
_

cmb
1st March 2014, 21:20
All widgets call into the current QStyle's API to delegate each part of the drawing.
My suggestion is to look at the code of QProgressBar and see which methods it calls with which arguments and then repeat all those that you want not to change.

Cheers,
_

I'm still confused -- could you point me toward where I should be looking? I've only overridden paintEvent(), as shown below. My derived class allows both positive and negative values for the bar (with zero at the center), so I'm drawing the bar separately from the groove. The bar therefore needs to be sized differently from the groove, but the difference changes depending on the style in use.

I've looked in qprogressbar.cpp, but all I saw in paintEvent() was that it calls drawControl() once to handle the groove and the bar.


/**
* Draws a progress bar that extends left or right from the center point.
*/
void FuelTrimBar::paintEvent(QPaintEvent *)
{
int currentVal = this->value();
QStylePainter painter(this);
QStyleOptionProgressBarV2 bar;
bar.initFrom(this);
bar.minimum = m_minimumVal;
bar.maximum = m_maximumVal;
bar.progress = (currentVal >= 0) ? qAbs(m_maximumVal) : qAbs(m_minimumVal);

style()->drawControl(QStyle::CE_ProgressBarGroove, &bar, &painter, this);

// compute the dimensions and location of the bar
float percentOfWidth = (float)(qAbs(currentVal)) / (float)(m_maximumVal - m_minimumVal);
int left = bar.rect.topLeft().x();
int right = bar.rect.topRight().x();
int top = bar.rect.topLeft().y();
int height = bar.rect.bottomLeft().y() - top + 1;
int barWidth = (right - left) * percentOfWidth;
int midPoint = left + ((right - left) / 2);
int startPoint = (currentVal >= 0) ? midPoint : midPoint - barWidth;

bar.rect = QRect(startPoint, top, barWidth + 2, height);
style()->drawControl(QStyle::CE_ProgressBarContents, &bar, &painter, this);
}

anda_skoa
2nd March 2014, 00:49
Hmm. Looks like you could reuse most of the code, no?
Just doing the progressbar contents differently.

Cheers,
_

cmb
2nd March 2014, 01:44
Hmm. Looks like you could reuse most of the code, no?
Just doing the progressbar contents differently.

Cheers,
_

I completely agree. However, the height of the CE_ProgressBarContents cannot simply be the same as the height of the groove. If I make them the same height, I end up with the progress bar that I posted in the first screenshot. CE_ProgressBarContents must have a smaller vertical dimension, but this is sensitive to the active style. That's why I was looking for a PixelMetric that described the difference in height.

anda_skoa
2nd March 2014, 10:27
What I mean is this:

the code of QProgressBar draws the groove, then calculates the rectange for the bar contents.

Can't you use the exact same code? At least for height? Just changing startPoint and barWidth?

Cheers,
_

cmb
2nd March 2014, 15:39
The code that I showed above is not in QProgressBar, it is in my subclass. The QProgressBar code looks like this:


void QProgressBar::paintEvent(QPaintEvent *)
{
QStylePainter paint(this);
QStyleOptionProgressBarV2 opt;
initStyleOption(&opt);
paint.drawControl(QStyle::CE_ProgressBar, opt);
d_func()->lastPaintedValue = d_func()->value;
}

As you can see, it just depends on the style to draw the entire control, which happens like this:


case CE_ProgressBar:
if (const QStyleOptionProgressBar *pb
= qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
QStyleOptionProgressBarV2 subopt = *pb;
subopt.rect = subElementRect(SE_ProgressBarGroove, pb, widget);
proxy()->drawControl(CE_ProgressBarGroove, &subopt, p, widget);
subopt.rect = subElementRect(SE_ProgressBarContents, pb, widget);
proxy()->drawControl(CE_ProgressBarContents, &subopt, p, widget);
if (pb->textVisible) {
subopt.rect = subElementRect(SE_ProgressBarLabel, pb, widget);
proxy()->drawControl(CE_ProgressBarLabel, &subopt, p, widget);
}
}
break;

It doesn't change the rectangle for the progress bar contents -- unless that's done somewhere in one of the QStyle subclasses. Still not sure what I should be looking for.

anda_skoa
2nd March 2014, 16:45
Ah, I see, sorry.

Hmm. Doesn't this line calculate the content rectangle?


subopt.rect = subElementRect(SE_ProgressBarContents, pb, widget);


Cheers,
_

cmb
2nd March 2014, 18:43
Ah, I see, sorry.

Hmm. Doesn't this line calculate the content rectangle?


subopt.rect = subElementRect(SE_ProgressBarContents, pb, widget);


Cheers,
_

Yes! That was it. Thank you for pointing that out; it was right in front of me but I didn't see it.

I now call subElementRect() for the progress bar contents before adjust the start and end point, and the bar is draw with the correct height for the style in use.