在样式化的QSlider上,刻度标记消失了。

7
我正在使用 Qt 5.3 并尝试样式化一个 QSlider。然而,当我应用我的样式表时,刻度标记消失了。有谁知道如何保持样式而不影响刻度标记吗?
以下是样式表:
QSlider::groove:horizontal
{
    border: 1px inset #B0B0B0;
    background-color: #EAEAEA;
    height: 2px;
}

QSlider::Handle
{   
    border: 1px solid black;
    background: #B0B0B0;                        
    background-image: url(:/metal_background_small);    
    width: 12px;
    margin: -8px 0;
}

QSlider::Handle:Hover
{   
    border: 1px solid black;
    background: #707070;                        
    background-image: url(:/metal_background_small);    
}

QSlider::sub-page
{
/*  margin: 7px 1px 7px 0px;*/
    height: 2px;
    background: #05bcfe;
}

2
我注意到在很多小部件上,如果你开始使用样式表来设置样式,你必须定义所有的东西,否则它将被忽略。我无法确定这是否是有意的,对我来说更像是一个错误。 - Bowdzone
2个回答

7

Qt样式表和刻度标记不能很好地协同工作。最简单的解决方案是子类化QSlider并重新实现paint_event。

virtual void paintEvent(QPaintEvent *ev)
{

    QStylePainter p(this);
    QStyleOptionSlider opt;
    initStyleOption(&opt);

    QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);

    // draw tick marks
    // do this manually because they are very badly behaved with style sheets
    int interval = tickInterval();
    if (interval == 0)
    {
        interval = pageStep();
    }

    if (tickPosition() != NoTicks)
    {
        for (int i = minimum(); i <= maximum(); i += interval)
        {
            int x = round((double)((double)((double)(i - this->minimum()) / (double)(this->maximum() - this->minimum())) * (double)(this->width() - handle.width()) + (double)(handle.width() / 2.0))) - 1;
            int h = 4;
            p.setPen(QColor("#a5a294"));
            if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
            {
                int y = this->rect().top();
                p.drawLine(x, y, x, y + h);
            }
            if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
            {
                int y = this->rect().bottom();
                p.drawLine(x, y, x, y - h);
            }

        }
    }

    // draw the slider (this is basically copy/pasted from QSlider::paintEvent)
    opt.subControls = QStyle::SC_SliderGroove;
    p.drawComplexControl(QStyle::CC_Slider, opt);

    // draw the slider handle
    opt.subControls = QStyle::SC_SliderHandle;
    p.drawComplexControl(QStyle::CC_Slider, opt);
}

相关的Qt Bug报告:https://bugreports.qt.io/browse/QTBUG-3304,https://bugreports.qt.io/browse/QTBUG-3564 - Damian Dixon

2

我不得不修改之前的答案以考虑到Qt的CSS margin属性(如果手柄的margin为0,则该答案仅适用)。我还需要在绘制滑块和手柄之后绘制刻度线,可能是因为它被绘制在刻度线上方。

在绘制刻度线时,只有在将手柄的margin和一半的宽度进行平移后才开始绘制。最后一个刻度线也必须与滑块右侧的距离相似。请参见:drawing area image

virtual void paintEvent(QPaintEvent *event)
{
    QStylePainter p(this);
    QStyleOptionSlider styleOptions;
    initStyleOption(&styleOptions);

    // Rectangle representing the slider's handle (position and size).
    const QRect handleRectangle =
    style()->subControlRect(QStyle::CC_Slider, &styleOptions, QStyle::SC_SliderHandle, this);

    // Draw the slider (this is basically copy/pasted from QSlider::paintEvent).
    styleOptions.subControls = QStyle::SC_SliderGroove;
    p.drawComplexControl(QStyle::CC_Slider, styleOptions);

    // Draw the slider handle.
    styleOptions.subControls = QStyle::SC_SliderHandle;
    p.drawComplexControl(QStyle::CC_Slider, styleOptions);

    // Draw tick marks.
    // Do this manually because they are very badly behaved with style sheets.
    int interval = tickInterval();
    if (interval == 0)
    {
        interval = pageStep();
    }

    if (tickPosition() != NoTicks)
    {
        // This is the horizontal margin of the slider's *handle*, as defined in the stylesheet.
        constexpr float margin = 25;

        const float handleWidth = static_cast<float>(handleRectangle.width());
        const float handleHalfWidth = handleWidth / 2.0f;
        const float sliderValueRange = static_cast<float>(this->maximum() - this->minimum());
        // Drawing range = control's width, minus twice the handle half width (one on each side), minus twice the margin (one on each side).
        const float drawingRange = static_cast<float>(this->width()) - handleWidth - 2.0f * margin;
        const float factor = drawingRange / sliderValueRange;
    
        for (int i = minimum(); i <= maximum(); i += interval)
        {
            // Height of the ticks' bars to draw.
            constexpr int tickHeight = 5;

            const int offsetValueSpace = i - minimum(); // How far from the slider's minimum value we are.
            const float offsetDrawingSpace = factor * static_cast<float>(offsetValueSpace) + handleHalfWidth + margin; // Where to draw in the horizontal range.
            const int x = static_cast<int>(offsetDrawingSpace);

            p.setPen(QColor{255, 255, 255, 255});
            if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
            {
                const int y = this->rect().top();
                p.drawLine(x, y, x, y + tickHeight);
            }
            if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
            {
                const int y = this->rect().bottom();
                p.drawLine(x, y, x, y - tickHeight);
            }
        }
    }
}

使用Qt的CSS定义的边距为:

MySlider::handle:horizontal {
    margin: -5px 25px; /* Match the 'margin' constexpr in the paint event. */
    ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接