最近一直都在折腾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才能满足要求,上面的方法感觉上是邪门歪道。
最后,第一次写博客。可能存在很多问题,有错误的地方直接指出来。