如何使用固定大小的句柄制作QScrollBar?

时间:2011-10-10 08:43:40

标签: css qt

我必须使用固定大小的句柄制作滚动条,因为它的背景图像在缩放时会变得难看。我使用以下样式表:

QScrollBar::handle:vertical {
  border-image:url(:/images/handle.png);
  min-height: 47px;
  max-height: 47px;
  height: 47px;
  width:10px;
}

但似乎max-height不是有效的属性。如何防止手柄缩放?

2 个答案:

答案 0 :(得分:1)

小技巧,来自Qt源代码: myScrollbar.h

class myScrollBar : public QScrollBar
{
    Q_OBJECT
public:
    myScrollBar(Qt::Orientation orientation, QWidget *parent = 0);
    void setSliderLength(int length);
protected:
    void paintEvent(QPaintEvent *);

private:
    QRect subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, /*const*/ QWidget *widget);

    QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect);

    int sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown);

private:
    int _sliderLength;
};

myScrollbar.cpp

myScrollBar::myScrollBar(Qt::Orientation orientation, QWidget *parent)
    : QScrollBar(orientation, parent),
      _sliderLength(100)
{

}
void myScrollBar::paintEvent(QPaintEvent *e)
{
    qDebug() << "scrollbar paintevent";

    //Q_D(QScrollBar);
    QScrollBar::paintEvent(e);
    QPainter painter(this);
    QStyleOptionSlider opt;
    initStyleOption(&opt);
    opt.subControls = QStyle::SC_All;
    QWidget *widget = this;
    //        if (d->pressedControl) {
    //            opt.activeSubControls = (QStyle::SubControl)d->pressedControl;
    //            if (!d->pointerOutsidePressedControl)
    //                opt.state |= QStyle::State_Sunken;
    //        } else {
    //            opt.activeSubControls = (QStyle::SubControl)d->hoverControl;
    //        }
    QPainter *p = &painter;
    //style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this);
    if (const QStyleOptionSlider *scrollbar = &opt) {
        // Make a copy here and reset it for each primitive.
        QStyleOptionSlider newScrollbar = *scrollbar;
        QStyle::State saveFlags = scrollbar->state;

        if (scrollbar->subControls & QStyle::SC_ScrollBarSubLine) {
            newScrollbar.state = saveFlags;
            newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarSubLine, widget);
            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarSubLine))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
                style()->drawControl(QStyle::CE_ScrollBarSubLine, &newScrollbar, p, widget);
            }
        }
        if (scrollbar->subControls & QStyle::SC_ScrollBarAddLine) {
            newScrollbar.rect = scrollbar->rect;
            newScrollbar.state = saveFlags;
            newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarAddLine, widget);
            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarAddLine))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
                style()->drawControl(QStyle::CE_ScrollBarAddLine, &newScrollbar, p, widget);
            }
        }
        if (scrollbar->subControls & QStyle::SC_ScrollBarSubPage) {
            newScrollbar.rect = scrollbar->rect;
            newScrollbar.state = saveFlags;
            newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarSubPage, widget);
            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarSubPage))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
                style()->drawControl(QStyle::CE_ScrollBarSubPage, &newScrollbar, p, widget);
            }
        }
        if (scrollbar->subControls & QStyle::SC_ScrollBarAddPage) {
            newScrollbar.rect = scrollbar->rect;
            newScrollbar.state = saveFlags;
            newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarAddPage, widget);
            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarAddPage))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
                style()->drawControl(QStyle::CE_ScrollBarAddPage, &newScrollbar, p, widget);
            }
        }
        if (scrollbar->subControls & QStyle::SC_ScrollBarFirst) {
            newScrollbar.rect = scrollbar->rect;
            newScrollbar.state = saveFlags;
            newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarFirst, widget);
            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarFirst))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
                style()->drawControl(QStyle::CE_ScrollBarFirst, &newScrollbar, p, widget);
            }
        }
        if (scrollbar->subControls & QStyle::SC_ScrollBarLast) {
            newScrollbar.rect = scrollbar->rect;
            newScrollbar.state = saveFlags;
            newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarLast, widget);
            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarLast))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
                style()->drawControl(QStyle::CE_ScrollBarLast, &newScrollbar, p, widget);
            }
        }
        if (scrollbar->subControls & QStyle::SC_ScrollBarSlider) {

            newScrollbar.rect = scrollbar->rect;

            newScrollbar.state = saveFlags;
            QRect rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarSlider, widget);
            newScrollbar.rect = QRect(rect.topLeft(), QSize(rect.width(), 100));

            if (newScrollbar.rect.isValid()) {
                if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarSlider))
                    newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);

                style()->drawControl(QStyle::CE_ScrollBarSlider, &newScrollbar, p, widget);

                if (scrollbar->state & QStyle::State_HasFocus) {
                    QStyleOptionFocusRect fropt;
                    fropt.QStyleOption::operator=(newScrollbar);
                    fropt.rect.setRect(newScrollbar.rect.x() + 2, newScrollbar.rect.y() + 2,
                                       newScrollbar.rect.width() - 5,
                                       newScrollbar.rect.height() - 5);
                    style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, p, widget);
                }
            }
        }
    }

}

void myScrollBar::setSliderLength(int length)
{
    _sliderLength = length;
}

QRect myScrollBar::subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, /*const*/ QWidget *widget)
{
    QRect ret;
    switch (cc) {
    case QStyle::CC_ScrollBar:
        if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
            const QRect scrollBarRect = scrollbar->rect;
            int sbextent = 0;
            if (!style()->styleHint(QStyle::SH_ScrollBar_Transient, scrollbar, widget))
                sbextent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, scrollbar, widget);
            int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
                              scrollBarRect.width() : scrollBarRect.height()) - (sbextent * 2);
            int sliderlen;

            // calculate slider length
            if (scrollbar->maximum != scrollbar->minimum) {
                uint range = scrollbar->maximum - scrollbar->minimum;
                sliderlen = (qint64(scrollbar->pageStep) * maxlen) / (range + scrollbar->pageStep);

                int slidermin = style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, scrollbar, widget);
                if (_sliderLength < slidermin || range > INT_MAX / 2)
                    _sliderLength = slidermin;
                if (_sliderLength > maxlen)
                    _sliderLength = maxlen;
                //length of the slider
                sliderlen = _sliderLength;
            } else {
                sliderlen = maxlen;
            }

            int sliderstart = sbextent + this->sliderPositionFromValue(scrollbar->minimum,
                                                                       scrollbar->maximum,
                                                                       scrollbar->sliderPosition,
                                                                       maxlen - sliderlen,
                                                                       scrollbar->upsideDown);

            switch (sc) {
            case QStyle::SC_ScrollBarSubLine:            // top/left button
                if (scrollbar->orientation == Qt::Horizontal) {
                    int buttonWidth = qMin(scrollBarRect.width() / 2, sbextent);
                    ret.setRect(0, 0, buttonWidth, scrollBarRect.height());
                } else {
                    int buttonHeight = qMin(scrollBarRect.height() / 2, sbextent);
                    ret.setRect(0, 0, scrollBarRect.width(), buttonHeight);
                }
                break;
            case QStyle::SC_ScrollBarAddLine:            // bottom/right button
                if (scrollbar->orientation == Qt::Horizontal) {
                    int buttonWidth = qMin(scrollBarRect.width()/2, sbextent);
                    ret.setRect(scrollBarRect.width() - buttonWidth, 0, buttonWidth, scrollBarRect.height());
                } else {
                    int buttonHeight = qMin(scrollBarRect.height()/2, sbextent);
                    ret.setRect(0, scrollBarRect.height() - buttonHeight, scrollBarRect.width(), buttonHeight);
                }
                break;
            case QStyle::SC_ScrollBarSubPage:            // between top/left button and slider
                if (scrollbar->orientation == Qt::Horizontal)
                    ret.setRect(sbextent, 0, sliderstart - sbextent, scrollBarRect.height());
                else
                    ret.setRect(0, sbextent, scrollBarRect.width(), sliderstart - sbextent);
                break;
            case QStyle::SC_ScrollBarAddPage:            // between bottom/right button and slider
                if (scrollbar->orientation == Qt::Horizontal)
                    ret.setRect(sliderstart + sliderlen, 0,
                                maxlen - sliderstart - sliderlen + sbextent, scrollBarRect.height());
                else
                    ret.setRect(0, sliderstart + sliderlen, scrollBarRect.width(),
                                maxlen - sliderstart - sliderlen + sbextent);
                break;
            case QStyle::SC_ScrollBarGroove:
                if (scrollbar->orientation == Qt::Horizontal)
                    ret.setRect(sbextent, 0, scrollBarRect.width() - sbextent * 2,
                                scrollBarRect.height());
                else
                    ret.setRect(0, sbextent, scrollBarRect.width(),
                                scrollBarRect.height() - sbextent * 2);
                break;
            case QStyle::SC_ScrollBarSlider:
                if (scrollbar->orientation == Qt::Horizontal)
                    ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height());
                else
                    ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen);

                break;
            default:
                break;
            }
            ret = visualRect(scrollbar->direction, scrollBarRect, ret);
        }
        return ret;
    }
}

QRect myScrollBar::visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
{
    if (direction == Qt::LeftToRight)
        return logicalRect;
    QRect rect = logicalRect;
    rect.translate(2 * (boundingRect.right() - logicalRect.right()) +
                   logicalRect.width() - boundingRect.width(), 0);
    return rect;
}

int myScrollBar::sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown)
{
    if (span <= 0 || logicalValue < min || max <= min)
        return 0;
    if (logicalValue > max)
        return upsideDown ? span : min;

    uint range = max - min;
    uint p = upsideDown ? max - logicalValue : logicalValue - min;

    if (range > (uint)INT_MAX/4096) {
        double dpos = (double(p))/(double(range)/span);
        return int(dpos);
    } else if (range > (uint)span) {
        return (2 * p * span + range) / (2*range);
    } else {
        uint div = span / range;
        uint mod = span % range;
        return p * div + (2 * p * mod + range) / (2 * range);
    }
    // equiv. to (p * span) / range + 0.5
    // no overflow because of this implicit assumption:
    // span <= 4096
}

例如:

myScrollBar *bar = new myScrollBar(Qt::Vertical, ui->treeWidget);
ui->treeWidget->setVerticalScrollBar(bar);

答案 1 :(得分:-1)

使用 这个jquery插件http://jscrollpane.kelvinluck.com/