Reimplement QSlider paint-Event



  • Hi,

    I would like to change the looks of the QSlider. Stylesheets won't help in this case so I decided to subclass QSlider and overwrite the paintEvent(QPaintEvent *event).

    However, I have some trouble with graphical bugs and also don't know how to approach this correctly.

    The first problem I have is that my handler can reach outside the bounding-Box of the Slider. This is actually problem of the code. I know I could fixe it by scaling / moving my graphicle elements a bit. However, I don't know how to fix this without messing up the hitbox for the mouse-interaction. Do you know how the QSlider itself deals with this problem?

    The second problem I have is a graphical glitch I see whenever I let go of the handler or draw the handler out of the slider bar. (I've linked two screenshots) It's a simple brigth line near the handler which isn't supposed to be there.

    My code is actually quite simple. Here are the important bits:

    @
    // calculate slider bar rectangle
    QRect sliderRect = event->rect();
    int width = sliderRect.width();
    int height = sliderRect.height();
    sliderRect.translate(0, (float)height*0.4);
    sliderRect.setHeight(sliderRect.height()*0.2);

    // draw the slider bar rectangle .....

    // calculate handler rectangle
    QRect handlerRect = event->rect();
    handlerRect.translate(0, (float)height*0.25);
    handlerRect.setWidth(handlerRect.height()*0.15);
    handlerRect.setHeight(handlerRect.height()*0.5);
    // calculate the position in pixel and offset half the handler width
    int handlerPos = ((float)(this->value()-this->minimum())/(float)this->maximum()) * event->rect().width() - handlerRect.width()*0.5;
    handlerRect.translate(handlerPos, 0);
    @

    Here are some screens with the graphical problem. The line is marked with the red box. What should be visible are the two rectangles with transparent fill.
    !https://studi.f4.htw-berlin.de/~s0539750/QSlider1.jpg(Example 1)!
    !https://studi.f4.htw-berlin.de/~s0539750/QSlider2.jpg(Example 2)!

    I hope you can help me. :)



  • Hi,

    If you would like to change just the looks of slider widget, you can select the approach of changing widget's style. For example, you subclass the QProxyStyle and set it to widget.

    Here are two functions you might modify,

    @void MyStyle::drawComplexControl(ComplexControl control,
    const QStyleOptionComplex* option,
    QPainter* painter,
    const QWidget* widget) const
    {
    if (control == CC_Slider) {
    if (const QStyleOptionSlider* slider = qstyleoption_cast<const QStyleOptionSlider*>(option)) {
    // paint groove
    painter->setPen(Qt::white);
    painter->setBrush(Qt::gray);
    painter->drawRect(subControlRect(CC_Slider, option, SC_SliderGroove, widget));
    // paint handle
    painter->setPen(QColor(255, 170, 0));
    painter->setBrush(QColor(255, 170, 0, 120));
    painter->drawRect(subControlRect(CC_Slider, option, SC_SliderHandle, widget));

            return;
        }
    }
    
    QProxyStyle::drawComplexControl(control, option, painter, widget);
    

    }

    QRect MyStyle::subControlRect(ComplexControl control,
    const QStyleOptionComplex *option,
    SubControl subControl,
    const QWidget *widget) const
    {
    QRect rect = QProxyStyle::subControlRect(control, option, subControl, widget);

    if (control == CC_Slider)
    {
        if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
            if (subControl == SC_SliderGroove) {
                (slider->orientation == Qt::Horizontal) 
                    ? rect.setHeight(slider->rect.height() * 0.2)
                    : rect.setWidth(slider->rect.width() * 0.2);
                rect.moveCenter(slider->rect.center());
            }
        }
    }
    return rect;
    

    }@

    and you can use this class like this,
    @MyStyle* style = new MyStyle(qApp->style());
    slider->setStyle(style);@



  • Hi,

    I fixed the function like this: Instead of using event->rect(), I used the bounding rectangle in the QSlider-class. It looks like the paint-function gets called for multiple parts of the slider which is in my opinion stupid. (The function shoudl be called once for an object and thets it)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.