QDial 自定义样式

最近一直都在折腾QDial这个控件,其实吧,我的要求很简单就是更改一下表盘颜色,和滑块颜色。我原以为简单使用setStyleSheet就可以轻松实现,像background、QDial::handle。结果却是这样的:

    QDial dial;
    dial.setGeometry(0, 0, 100, 100);
    dial.setValue(0);
    dial.setWrapping(true);
    dial.setStyleSheet("QDial{"
                       "    background: gray;"
                       "}"
                       ""
                       "QDial::handle{"
                       "    backgroudn: black;"
                       "}");

 

看运行结果似乎只是改了背景颜色而已。后面也一直在找QDial的样式表,但是并没有找到像样的有用的消息。基本都是叫你重写一个Dial控件,重新实现一遍Dial的功能。原本简单的一个旋钮,只是想要简单的递增和递减功能。不想搞太复杂,就简单换个颜色而已。

         我目前的目标是想保留QDial的基本功能,重新实现它的样式。直接继承QDial实现paintEvent?我并不想这样。于是,我把目光投向的QStyle。我们都知道Gui控件样式都通过QStyle一步一步的画出来的。然而直接继承QStyle写样式,过于麻烦,要实现太多功能。那么,它的子类QProxyStyle就是很好的选择。重新实现以下函数:


virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const override;

但是,再写的过程中又遇到各种问题,获取不到QDial样式的三个部件位置:

//    CC_Dial---QDial控件样式
//    QDial样式分为3部分
//    SC_DialGroove---QDial表盘
//    SC_DialHandle---QDial手柄
//    SC_DialTickmarks---QDial刻度
//    详细请参考官方文档

void DialStyle::drawComplexControl(QStyle::ComplexControl which, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    if(which == CC_Dial){
        if(const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)){
            //这里我试图获取QDial的Groove的矩形位置
            //然而并没有用
            QRect groove = subControlRect(CC_Dial, optionSlider, SC_DialGroove, widget);
        }
        
       drawDialSlider(SC_DialHandle, option, painter, widget);
    }else {
        QProxyStyle::drawComplexControl(which, option, painter, widget);
    }
}

直接报出一条警告   QCommonStyle::subControlRect: Case 6 not handled  意思大概说是这个函数的没有实现编号6,索引6没有处理(CC_Dial的枚举值就是6)。上下折腾了这么久,到这里就很无奈。后面跑去看QCommonStyle::subControlRect函数的源码(QCommonStyle是QProxyStyle的父类),也是苦笑不得。源码里面其他的枚举基本都有返回,就是CC_Dial没有写。(你说是不是QDial的开发者忘记添加了?)

后面想了想,只能死马当活马医了。硬是给它画出来:

// DialStyle.h

#ifndef DIALSTYLE_H
#define DIALSTYLE_H

#include <QProxyStyle>
#include <QPainter>
#include <QStyleOptionSlider>
#include <QDial>

class DialStyle : public QProxyStyle
{
public:
    explicit DialStyle();

    void drawComplexControl(ComplexControl which,const QStyleOptionComplex *option,QPainter *painter,const QWidget *widget = nullptr) const override;
    void drawDialStyle(SubControl which, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const;

};

#endif // DIALSTYLE_H
//DialStyle.cpp

#include "dialstyle.h"

#include <QPainter>
#include <QStyleOptionComplex>
#include <QDebug>
#include <QWidget>
#include <QApplication>

DialStyle::DialStyle()
{

}

void DialStyle::drawComplexControl(QStyle::ComplexControl which, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    if(which == CC_Dial){
        drawDialStyle(SC_DialHandle, option, painter, widget);
    }else {
        QProxyStyle::drawComplexControl(which, option, painter, widget);
    }
}

void DialStyle::drawDialStyle(SubControl which, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    Q_UNUSED(which);
    Q_UNUSED(widget);
    if(const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)){

        int grooveDia = qMin<int>(optionSlider->rect.width(), optionSlider->rect.height());
        QRect groove(optionSlider->rect.x(), optionSlider->rect.y(), grooveDia, grooveDia);

        int movePosX = (optionSlider->rect.width()-grooveDia)/2;
        int movePosY = (optionSlider->rect.height()-grooveDia)/2;

        painter->translate(movePosX, movePosY);

        //画表盘背景
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing, true);
        painter->setBrush(Qt::gray);
        painter->setPen(Qt::NoPen);
        painter->drawRoundedRect(groove, grooveDia/2, grooveDia/2);

        painter->translate( groove.width()/2, groove.height()/2);

        //画手柄
        double handleDia = grooveDia/5;
        double handlePosX = -handleDia/2;
        double handlePosY = (grooveDia/2) * 0.5;
        QRectF handle(handlePosX, handlePosY, handleDia, handleDia);
        painter->setBrush(Qt::black);
        qreal rot = optionSlider->sliderValue/(qreal)(optionSlider->maximum-optionSlider->minimum)*359.0;
        painter->rotate(rot);
        qDebug() << optionSlider->sliderValue;
        painter->drawRoundedRect(handle, handleDia/2, handleDia/2);
        painter->restore();
    }
}
//main.cpp

#include "mainwindow.h"

#include <QApplication>
#include <QDial>
#include "dialstyle.h"

int main(int argc, char *argv[])
{

    QApplication a(argc, argv);

    QDial dial;
    dial.setWrapping(true);
    dial.setStyle(new DialStyle);
    dial.show();

}

最后实现的效果:

 其实上面画的代码多多少少有点问题,但基本已经符合我的要求。如果,要实现更多精细的功能。我觉得还得是重写Dial才能满足要求,上面的方法感觉上是邪门歪道。

最后,第一次写博客。可能存在很多问题,有错误的地方直接指出来。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值