`QStyle`自定义重绘`QSlider`控件

简介: 根据QStyle的继承关系和重绘原理;通过实现一个继承QCommonStyle类的实现,实现自己的自定义控件QSlider控件。

本博文的简述or解决问题?

详情: 见简介


编程环境: deepin 15.11 x64 专业版 Kernel: x86_64 Linux 4.15.0-30deepin-generic

编程软件: Qt Creator 4.8.2 (Enterprise)Qt 5.9.8


系列博文:


运行效果:

先上一张最终的重绘运行效果图

运行代码,在 main() 函数里面:

QApplication app(argc, argv);
    qApp->setStyle("chameleon");

    QWidget wTemp;
    wTemp.resize(800, 600);
    
//    NoTicks = 0,
//    TicksAbove = 1,
//    TicksLeft = TicksAbove,
//    TicksBelow = 2,
//    TicksRight = TicksBelow,
//    TicksBothSides = 3

	QHBoxLayout *layout = new QHBoxLayout(&wTemp);
    QSlider *slider1 = new QSlider(&wTemp);               //竖直刻度在右侧的Slider
    slider1->setOrientation(Qt::Vertical);
    slider1->setTickPosition(QSlider::TicksRight);
    slider1->setTickInterval(10);
    slider1->resize(40, 300);

    QSlider *slider2 = new QSlider(&wTemp);              //竖直刻度在左侧的Slider
    slider2->setOrientation(Qt::Vertical);
    slider2->setTickPosition(QSlider::TicksLeft);
    slider2->setTickInterval(10);
    slider2->resize(40, 300);
    slider2->move(150, 0);

    QSlider *slider3 = new QSlider(&wTemp);             //水平刻度在下侧的Slider
    slider3->setOrientation(Qt::Horizontal);
    slider3->setTickPosition(QSlider::TicksBelow);
    slider3->resize(300, 40);
    slider3->setTickInterval(10);
    slider3->move(0, 400);

    QSlider *slider4 = new QSlider(&wTemp);             //水平刻度在上侧的Slider
    slider4->setOrientation(Qt::Horizontal);
    slider4->setTickPosition(QSlider::TicksAbove);
    slider4->resize(300, 40);
    slider4->setTickInterval(10);
    slider4->move(400, 400);

    QSlider *slider5 = new QSlider(&wTemp);             //竖直刻度在两侧的Slider
    slider5->setOrientation(Qt::Vertical);
    slider5->setTickPosition(QSlider::TicksBothSides);
    slider5->resize(40, 300);
    slider5->setTickInterval(10);
    slider5->move(300, 0);

    QSlider *slider6 = new QSlider(&wTemp);            //水平刻度在两侧的Slider
    slider6->setOrientation(Qt::Horizontal);
    slider6->setTickPosition(QSlider::TicksBothSides);
    slider6->resize(300, 40);
    slider6->setTickInterval(10);
    slider6->move(0, 500);

    wTemp.show();
    return app.exec();

QSlider属性:

  • Qt文档:

先看Qt官方文档介绍,我搽,就这么两个属性???然后大致浏览完了整篇。怎么给我一点,怎么只有这么一点讲解的内容啊!!!这可不行,谁受得了啊 ,然后继续看源码,看其继承的基类QAbstractSlider等之后。这还差不多。不然我怎么使用QStyle重绘这个控件

  • tickInterval : int
    此属性保存tickmarks之间的间隔这是一个值间隔,而不是像素间隔。如果为0,滑块将在singleStep和pageStep之间进行选择。
  • tickPosition : TickPosition
    此属性保存此滑块的tickmark位置,有效值由QSlider::TickPosition enum描述。默认值是QSlider:: notice。

刻度条绘画方向:

ConstantDescription
QSlider::NoTicks不显示刻度
QSlider::TicksBothSides两边都显示刻度
QSlider::TicksAbove刻度显示在上边(水平)
QSlider::TicksBelow刻度显示在下边(水平)
QSlider::TicksLeft刻度显示在左边(竖直)
QSlider::TicksRight刻度显示在右边(竖直)

QSlider的摆放方向:

orientation : Qt::OrientationDescription
Qt::Vertical滑动条竖直绘画
Qt::Horizontal滑动条水平绘画

其他几个涉及QStyle重绘的重要属性:

val含义
minimum滑动条最小值
maximum滑动条最大值
singleStep在min-max之间显示的步长,移动一步的改变数值
pageStep用于计算刻度的个数(有阈值限制,不完全按这个来,没详细研究,柑橘用来有点迷);
value当前的显示数值(在min-max之间,也是本信号的槽的参数的数值)
sliderPosition??
tickInterval两个刻度之间的间隔数值(重绘使用)
tickPosition刻度的位置

注意: pageStep 这个用于计算刻度的个数(有阈值限制,不完全按这个来,没详细研究,柑橘用来有点迷); 刻度个数 - 1 = 刻度间隔的个数 = (span - 0) / pageStep; 关于0, span, min, max, val 的关系,参见sliderPositionFromValue()的实现 [此处特指qfusionstyle.cpp 里面的, 不知道qcommstyle.cpp实现原理是否相同?]


理解属性步长sigleStep、pageSteop:

因为QSlider = 滑块(句柄)+ 滑槽 + 刻度(矩形)

创建一个简单的小例子,核心代码如下:

void Widget::on_sliderHor_valueChanged(int value)
{
    int minimum = ui->sliderHor->minimum();                 //滑动条最小值
    int maximum = ui->sliderHor->maximum();                 //滑动条最大值
    int sigleStep = ui->sliderHor->singleStep();            //在min~max之间显示的步长,移动一步的改变数值
    int pageSteop = ui->sliderHor->pageStep();              //用于计算刻度的个数(有阈值限制,不完全按这个来)
    int val = ui->sliderHor->value();                      //当前的显示数值(在min~max之间,也是本信号的槽的参数的数值)
    int sliderPosition = ui->sliderHor->sliderPosition();   //?? 不是很清楚
    int tickinterval = ui->sliderHor->tickInterval();       //两个刻度之间的间隔数值(重绘使用)
    int tickPosition = ui->sliderHor->tickPosition();       //刻度的位置

    QString str = QString("value:%1,  minimum:%2,  maximum:%3,  sigleStep:%4,  pageSteop:%5,  val:%6,  sliderPosition:%7,  tickinterval:%8,  tickPosition:%9").arg(value).arg(minimum).arg(maximum).arg(sigleStep).arg(pageSteop).arg(val).arg(sliderPosition).arg(tickinterval).arg(tickPosition);
                       
    qDebug()<<str;
}

其效果如下:有qDebug可以查看每一个数值的含义,以及变化可以看出其含义(每次按下按下一个方向→或←按键);就会显示一行数据, 重点观察sigleStep、sigleStep、pageSteop的数值;

感觉其上面这些矩形,大多是使用时候,而非更底层的重绘该空间使用的;而sliderPositiontickPosition才是重绘使用得。有了上面的基础之后,下面开始正经的重绘:


重绘QSlider:

重绘思路:

  • 先预先计算好滑块(矩形)+ 滑槽(矩形) + 刻度(矩形)
  • 对该部分矩形进行绘画

计算所需要的三个部分的矩形:

QRect CustomStyle::subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt,
                                     QStyle::SubControl sc, const QWidget *w) const
{
    switch (cc) {
    case CC_Slider: {
        if (const QStyleOptionSlider *option = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
            QRectF rect = option->rect;                                                    //Slider控件总的大小矩形
            int slider_size = proxy()->pixelMetric(PM_SliderControlThickness, opt, w);     //滑块的高度
//            int tick_size = proxy()->pixelMetric(PM_SliderTickmarkOffset, opt, w);         //刻度的高度
            QRectF slider_handle_rect = rect;                                              //滑块和滑漕的的最小公共矩形 (后面被用作临时且被改变的)

            if (option->orientation == Qt::Horizontal) {
                slider_handle_rect.setHeight(slider_size);
                if (option->tickPosition == QSlider::TicksAbove) slider_handle_rect.moveBottom(rect.bottom());
                if (option->tickPosition == QSlider::TicksBelow) slider_handle_rect.moveTop(rect.top());
                if (option->tickPosition == QSlider::TicksBothSides) slider_handle_rect.moveCenter(rect.center());
            } else {
                slider_handle_rect.setWidth(slider_size);
                if (option->tickPosition == QSlider::TicksRight)  slider_handle_rect.moveLeft(rect.left());
                if (option->tickPosition == QSlider::TicksLeft)   slider_handle_rect.moveRight(rect.right());
                if (option->tickPosition == QSlider::TicksBothSides) slider_handle_rect.moveCenter(rect.center());
            }

            QRectF rectStatic =  slider_handle_rect;   //rectStatic作为 滑块和滑漕的的最小公共矩形(不改变)

            switch (sc) {
            case SC_SliderGroove: {  //滑漕
                qreal groove_size = slider_size / 4.0;
                QRectF groove_rect;

                if (option->orientation == Qt::Horizontal) {
                    groove_rect.setWidth(slider_handle_rect.width());
                    groove_rect.setHeight(groove_size);
                } else {
                    groove_rect.setWidth(groove_size);
                    groove_rect.setHeight(slider_handle_rect.height());
                }

                groove_rect.moveCenter(slider_handle_rect.center());
                return groove_rect.toRect();
            }
            case SC_SliderHandle: {  //滑块
                int sliderPos = 0;
                int len = proxy()->pixelMetric(PM_SliderLength, option, w);
                bool horizontal = option->orientation == Qt::Horizontal;
                sliderPos = sliderPositionFromValue(option->minimum, option->maximum, option->sliderPosition,
                                                    (horizontal ? slider_handle_rect.width() : slider_handle_rect.height()) - len, option->upsideDown);
                if (horizontal) {
                    slider_handle_rect.moveLeft(slider_handle_rect.left() + sliderPos);
                    slider_handle_rect.setWidth(len);
                    slider_handle_rect.moveTop(rectStatic.top());
                } else {
                    slider_handle_rect.moveTop(slider_handle_rect.top() + sliderPos);
                    slider_handle_rect.setHeight(len);
                    slider_handle_rect.moveLeft(rectStatic.left());
                }

                return slider_handle_rect.toRect();
            }
            case SC_SliderTickmarks: {  //刻度的矩形
                QRectF tick_rect = rect;

                if (option->orientation == Qt::Horizontal) {
                    tick_rect.setHeight(rect.height() - slider_handle_rect.height());

                    if (option->tickPosition == QSlider::TicksAbove) {
                        tick_rect.moveTop(rect.top());
                    } else if (option->tickPosition == QSlider::TicksBelow) {
                        tick_rect.moveBottom(rect.bottom());
                    }
                } else {
                    tick_rect.setWidth(rect.width() - slider_handle_rect.width());

                    if (option->tickPosition == QSlider::TicksLeft) {
                        tick_rect.moveLeft(rect.left());
                    } else if (option->tickPosition == QSlider::TicksRight) {
                        tick_rect.moveRight(rect.right());
                    }
                }

                return tick_rect.toRect();
            }
            default:
                break;
            }
        }
        break;
    }
    default:
        break;
    }
    
    return QCommonStyle::subControlRect(cc, opt, sc, w);
}

再对其中每一个矩形(一共3个)进行重绘:

void ChameleonStyle::drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex *opt,
                                        QPainter *p, const QWidget *w) const
{
    switch (cc) {
    case CC_Slider : {
        if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
            //各个使用的矩形大小和位置
            QRectF rect = opt->rect;                                                                            //Slider控件最大的矩形(包含如下三个)
            QRectF rectHandle = proxy()->subControlRect(CC_Slider, opt, SC_SliderHandle, w);                    //滑块矩形
            QRectF rectSliderTickmarks = proxy()->subControlRect(CC_Slider, opt, SC_SliderTickmarks, w);        //刻度的矩形
            QRect rectGroove = proxy()->subControlRect(CC_Slider, opt, SC_SliderGroove, w);                     //滑槽的矩形

//            qDebug()<<"____04_____Slider控件最大的矩形(包含如下三个):"<<rect<<"  滑块矩形:"<<rectHandle<<"  刻度的矩形:"<<rectSliderTickmarks<<"   滑槽的矩形:"<<rectGroove<<endl;

//            //测试(保留不删)
            p->fillRect(rect, Qt::gray);
            p->fillRect(rectSliderTickmarks, Qt::blue);
            p->fillRect(rectGroove, Qt::red);
            p->fillRect(rectHandle, Qt::green);
            qDebug()<<"---rect:"<<rect<<"  rectHandle:"<<rectHandle<<"   rectSliderTickmarks:"<<rectSliderTickmarks<<"   rectGroove:"<<rectGroove;

            QPen pen;
            //绘画 滑槽(线)
            if (opt->subControls & SC_SliderGroove) {
                pen.setStyle(Qt::CustomDashLine);
                QVector<qreal> dashes;
                qreal space = 1.3;
                dashes << 0.1 << space;
                pen.setDashPattern(dashes);
                pen.setWidthF(3);
                pen.setColor(getColor(opt, QPalette::Highlight));
                p->setPen(pen);
                p->setRenderHint(QPainter::Antialiasing);

                if (slider->orientation == Qt::Horizontal) {
                    p->drawLine(QPointF(rectGroove.left(), rectHandle.center().y()), QPointF(rectHandle.left(), rectHandle.center().y()));
                    pen.setColor(getColor(opt, QPalette::Foreground));
                    p->setPen(pen);
                    p->drawLine(QPointF(rectGroove.right(), rectHandle.center().y()), QPointF(rectHandle.right(), rectHandle.center().y()));
                } else {
                    p->drawLine(QPointF(rectGroove.center().x(), rectGroove.bottom()), QPointF(rectGroove.center().x(),  rectHandle.bottom()));
                    pen.setColor(getColor(opt, QPalette::Foreground));
                    p->setPen(pen);
                    p->drawLine(QPointF(rectGroove.center().x(),  rectGroove.top()), QPointF(rectGroove.center().x(),  rectHandle.top()));
                }
            }

            //绘画 滑块
            if (opt->subControls & SC_SliderHandle) {
                pen.setStyle(Qt::SolidLine);
                p->setPen(Qt::NoPen);
                p->setBrush(getColor(opt, QPalette::Highlight));
                p->drawRoundedRect(rectHandle, DStyle::pixelMetric(DStyle::PM_FrameRadius), DStyle::pixelMetric(DStyle::PM_FrameRadius));
            }

            //绘画 刻度,绘画方式了参考qfusionstyle.cpp
            if ((opt->subControls & SC_SliderTickmarks) && slider->tickInterval) {                                   //需要绘画刻度
                p->setPen(opt->palette.foreground().color());
                int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, w);  //可用空间
                int interval = slider->tickInterval;                                       //标记间隔
//                int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, opt, w);      //标记偏移
//                int ticks = slider->tickPosition;                                          //标记位置

                int v = slider->minimum;
                int len = proxy()->pixelMetric(PM_SliderLength, slider, w);
                while (v <= slider->maximum + 1) {                                          //此处不添加+1的话, 会少绘画一根线
                    const int v_ = qMin(v, slider->maximum);
                    int pos = sliderPositionFromValue(slider->minimum, slider->maximum, v_, available) + len / 2;

                    if (slider->orientation == Qt::Horizontal) {
                        if (slider->tickPosition == QSlider::TicksBothSides) {              //两侧都会绘画, 总的矩形-中心滑槽滑块最小公共矩形
                            p->drawLine(pos, rect.top(), pos, rectHandle.top());
                            p->drawLine(pos, rect.bottom(), pos, rectHandle.bottom());
                        } else {
                            p->drawLine(pos, rectSliderTickmarks.top(), pos, rectSliderTickmarks.bottom());
                        }
                    } else {
                        if (slider->tickPosition == QSlider::TicksBothSides) {
                            p->drawLine(rect.left(), pos, rectHandle.left(), pos);
                            p->drawLine(rect.right(), pos, rectHandle.right(), pos);
                        } else {
                            p->drawLine(rectSliderTickmarks.left(), pos, rectSliderTickmarks.right(), pos);
                        }
                    }
                    // in the case where maximum is max int
                    int nextInterval = v + interval;
                    if (nextInterval < v)
                        break;
                    v = nextInterval;
                }
            }

        }
        break;
    }
    default:
        break;
    }

    DStyle::drawComplexControl(cc, opt, p, w);
}

若刻度异常情况(非bug):

注意: 下图中是使用pen.setStyle(Qt::DotLine);来绘画的,上面的代码修改为了pen.setStyle(Qt::CustomDashLine);来绘画,所以会**(看到的滑槽)**略有不一样;

当显示区域比较小的时候,而刻度条的个数又比较多的时候(密密麻麻的那种),当超过某一阈值时候,系统会自动压缩显示,一个变成**“胖瘦相间隔”**,此时如果将该粗窗口放大,则会被重绘画显示正常,刻度条均匀相间隔。

原图效果:

本来还以为是自己重新绘画的效果造成的,后面确定是过密形成的显示异常情况.就想着有没有能够的解决方法,能够重新绘画显示.想着参考QFusion 风格的实现,于是翻看源码,只看绘画刻度部分的Qt源码:

if (option->subControls & SC_SliderTickmarks) {
                painter->setPen(outline);
                int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
                int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
                int interval = slider->tickInterval;
                if (interval <= 0) {
                    interval = slider->singleStep;
                    if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
                                                        available)
                            - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
                                                              0, available) < 3)
                        interval = slider->pageStep;
                }
                if (interval <= 0)
                    interval = 1;

                int v = slider->minimum;
                int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
                while (v <= slider->maximum + 1) {
                    if (v == slider->maximum + 1 && interval == 1)
                        break;
                    const int v_ = qMin(v, slider->maximum);
                    int pos = sliderPositionFromValue(slider->minimum, slider->maximum,
                                                      v_, (horizontal
                                                           ? slider->rect.width()
                                                           : slider->rect.height()) - len,
                                                      slider->upsideDown) + len / 2;
                    int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);

                    if (horizontal) {
                        if (ticksAbove) {
                            painter->drawLine(pos, slider->rect.top() + extra,
                                              pos, slider->rect.top() + tickSize);
                        }
                        if (ticksBelow) {
                            painter->drawLine(pos, slider->rect.bottom() - extra,
                                              pos, slider->rect.bottom() - tickSize);
                        }
                    } else {
                        if (ticksAbove) {
                            painter->drawLine(slider->rect.left() + extra, pos,
                                              slider->rect.left() + tickSize, pos);
                        }
                        if (ticksBelow) {
                            painter->drawLine(slider->rect.right() - extra, pos,
                                              slider->rect.right() - tickSize, pos);
                        }
                    }
                    // in the case where maximum is max int
                    int nextInterval = v + interval;
                    if (nextInterval < v)
                        break;
                    v = nextInterval;
                }
            }

等等, 这根本没有考虑这个问题,好不好。而且感觉绘画刻度的方法,是对一个矩形矩形多次精确的计算,eeemmmmmmmmmm,这样子是不是有点复杂了了。感觉没有我的将这一个超大矩形,分割成为三个小矩形这一思路简单,然后在对每一块小矩形进行相应的绘画。


解决方法:

决定尝试一下其原生**QFusion风格()是怎么解决这个效果,当设置刻度间隔比较小的时候,显示宽度比较窄时候,这个东西出现了"胖瘦相互间隔",然后利用上面的一开始创建的小例子,改变步长和刻度间个和max值,看看效果**

甚至再次改变步长和刻度间个和max值,看看效果。过于密集,成了线

握草,握了个草,我握了个大草.hhhhhhhhhhhhhhhhhh,原来老哥你也没有设置这个问题啊,果断的出结论,这不是bug.果断不再继续修改了重绘画了.坏坏的笑了几下之后。

于是将一开始出现问题的地方,将该窗口最大化,然后局部拉大,看到这个效果(果然得到了验证):

最后总结:

这个不是bug,或者显示异常。冷静下来是思考:如此窄的矩形里面,显示如此多根刻度线,由于像素限制,只能后绘画的比较密集,当这个数值更大的时候,会发现,这个会变成一条直线(放大拉开显示,才会显示其实是均匀相间隔的).


思考总结:

  • 首先检查代码,是否是相关部分的代码逻辑有问题
  • 仍然觉得不应该之后,试一下Qt自带的是否会重现,排除是自己还是非自己原因
  • 改变相关的值,写小例子验证,查看效果
  • 发现经验:+1; 完美结束

互联网分享:

因为有着许许多多的热心网友的无私分享,从他们的博客中学习成长,学会很多,故也不辞辛苦也将自己的项目或经验整理成博客的形式,也提供给一起大家学习探讨与交流


系列地址:

QtExamples

欢迎 starfork 这个系列的 QT / DTK 学习,附学习由浅入深的目录。

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
### 回答1: 可以通过继承QSlider类并重写paintEvent()函数来自定义QSlider滑动条,同时可以通过设置QStyleOptionSlider中的subControls属性来设置滑块的形状为圆形。具体实现可以参考以下代码: ``` class CustomSlider : public QSlider { public: CustomSlider(QWidget *parent = nullptr) : QSlider(parent) { setStyleSheet("QSlider::groove:horizontal { height: 10px; background: #ddd; }" "QSlider::handle:horizontal { width: 20px; border-radius: 10px; background: #333; }"); } protected: void paintEvent(QPaintEvent *event) override { QSlider::paintEvent(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QStyleOptionSlider opt; initStyleOption(&opt); QRect grooveRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); QRect handleRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); QPoint center = handleRect.center(); painter.setPen(Qt::NoPen); painter.setBrush(QColor("#333")); painter.drawEllipse(center, handleRect.width() / 2, handleRect.height() / 2); } }; ``` 在上述代码中,我们通过设置QSlider的样式表来设置滑动条的样式,其中groove表示滑动条的轨道,handle表示滑块。在paintEvent()函数中,我们首先调用QSlider的paintEvent()函数来绘制默认的滑动条,然后获取滑动条的轨道和滑块的矩形区域,并计算出滑块的中心点。最后,我们使用QPainter绘制一个圆形,将其填充为黑色,并以滑块的中心点为圆心,滑块宽度的一半为半径进行绘制,从而实现了圆形滑块的效果。 ### 回答2: QT是一款跨平台的C++图形用户界面应用程序开发框架。在QT中,我们可以自定义QSlider滑动条以及滑块的形状。 要自定义QSlider滑动条,首先我们需要创建一个自定义的滑动条类,继承QSlider。在该类中,我们可以重写一些QSlider的虚函数,如paintEvent()、sliderChange()等,以实现自定义的滑动条样式和功能。 要实现圆形的滑块,我们可以通过设置滑块样式表来实现。在QSlider的子类中,通过重写paintEvent()函数,我们可以在滑动条上绘制自定义的滑块。 以下是一个自定义的QSlider滑动条,滑块为圆形的示例代码: ```cpp class CustomSlider : public QSlider { Q_OBJECT public: CustomSlider(QWidget *parent = nullptr) : QSlider(parent) { setStyleSheet("QSlider::handle {" " background: green;" " border-radius: 8px;" " width: 16px;" " height: 16px;" "}"); } protected: void paintEvent(QPaintEvent *event) override { QSlider::paintEvent(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); QRect grooveRect = style()->subControlRect(QStyle::CC_Slider, this, QStyle::SC_SliderGroove, this); int x = grooveRect.x() + grooveRect.height() / 2 - 8; int y = grooveRect.y() + grooveRect.height() / 2 - 8; painter.setBrush(QColor(51, 153, 255)); painter.setPen(Qt::NoPen); painter.drawEllipse(QRect(x, y, 16, 16)); } }; ``` 在上述代码中,我们重写了CustomSlider的构造函数和paintEvent()函数。构造函数中通过设置样式表,将滑块的背景设为绿色,圆角半径设为8px,并设置滑块的大小为16x16px。paintEvent()函数中,我们通过获取滑动条的轨道区域,计算滑块的位置,然后绘制一个蓝色圆形作为滑块。 我们可以在应用程序中使用CustomSlider类来替代QSlider类,从而实现自定义的滑动条和圆形滑块。 ### 回答3: 要自定义QSlider滑动条,使滑块圆形,可以通过重写QStyle类的drawComplexControl方法来实现。具体步骤如下: 1. 创建一个继承自QStyle自定义样式类,并重写drawComplexControl方法。 2. 在drawComplexControl方法中,首先调用父类的drawComplexControl方法,这样可以绘制默认样式的滑块。 3. 获取滑块的矩形区域,并将其设置为圆形。 4. 根据滑块的圆形矩形区域,绘制一个圆形。 5. 最后,将自定义样式类应用到QSlider控件上。 下面是实现上述步骤的示例代码: ```C++ #include <QtWidgets> class CustomSliderStyle : public QStyle { public: using QStyle::QStyle; void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = nullptr) const override { if (control == CC_Slider && option->subControls == SC_SliderHandle) { QStyleOptionSlider opt = *qstyleoption_cast<const QStyleOptionSlider*>(option); // 绘制默认样式的滑块 QStyle::drawComplexControl(control, option, painter, widget); // 获取滑块的矩形区域 QRect grooveRect = subControlRect(CC_Slider, option, SC_SliderHandle, widget); QRect handleRect = opt.rect; // 将滑块的矩形区域设置为圆形 handleRect.setSize(QSize(handleRect.width(), handleRect.width())); handleRect.moveCenter(grooveRect.center()); // 绘制圆形滑块 painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setPen(Qt::NoPen); painter->setBrush(opt.palette.buttonText()); painter->drawEllipse(handleRect); painter->restore(); } else { QStyle::drawComplexControl(control, option, painter, widget); } } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); QSlider slider; CustomSliderStyle customStyle; slider.setStyle(&customStyle); slider.show(); return app.exec(); } ``` 通过以上代码,可以自定义QSlider滑动条,使滑块变为圆形。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偕臧x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值