天天看点

Qt自定义类使用QSS换肤

文章目录

  • ​​一、前言​​
  • ​​二、效果展示​​
  • ​​三、具体步骤​​
  • ​​3.1、自定义继承自QWidget的类​​
  • ​​3.2、自定义类添加自定义属性及接口​​
  • ​​3.3、完整的时钟控件代码​​
  • ​​3.4、添加qss文件​​
  • ​​3.5、切换qss​​
  • ​​四、工程分享​​

一、前言

在Qt中,我们可以使用QSS来定制软件的样式,QSS提供了各种【选择器】、【属性】、【伪状态】等来帮助我们实现这一目的,但是似乎这些都是针对Qt提供的内部类,由于一些特定的需求,我们有些时候需要自定义控件,那自定义的控件不是Qt提供的内部类,能不能用QSS来定制样式呢?答案是可以的,接下来我们就来看看具体的步骤吧!

二、效果展示

Qt自定义类使用QSS换肤

三、具体步骤

3.1、自定义继承自QWidget的类

首先我们先正常自定义一个控件类,这个类必须继承自QWidget,因为QSS只对QWidget及其子类有效;

在这里拿很久之前写的时钟控件举例:

#ifndef STYLEDWIDGET_H
#define STYLEDWIDGET_H

#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QtMath>
#include <QTimer>

#define PI 3.14

class StyledWidget : public QWidget
{
    Q_OBJECT
public:
    explicit StyledWidget(QWidget *parent = nullptr);
    ~StyledWidget();
    
protected:
    void paintEvent(QPaintEvent *);//重写绘制事件函数
    void Init_Parameter();//初始化参数函数
    void Set_Mask(QPainter *);//设置窗体透明
    void Draw_Clock(QPainter *);//绘制时钟
    void Draw_Broad(QPainter *);//绘制时钟盘
    void Draw_Dial(QPainter *);//绘制刻度盘
    void Draw_Text(QPainter *);//绘制刻度值
    void Draw_Pointer(QPainter *);//绘制指针

private:
    QTimer *timer;//定时器
    QPoint Center_pos;//时钟圆心坐标
    int R_Edge;//外部圆半径
    int R_Inside;//内部圆半径
    int R_Center;//中心小圆半径
    int R_Pointer;//中心指针圆半径
    int Div_Max = 12;//大刻度值
    int Div_Min = 5;//小刻度值
    float BaseAngle = 270;//基础仰角
    int H;//时
    int M;//分
    int S ;//秒

private:
    QColor Color_Edge = QColor(0,0,0,255);//外部圆颜色
    QColor Color_Inside = QColor(255,255,255,255);//内部圆颜色
    QColor Color_Center = QColor(0,0,0,255);//中心小圆颜色
};

#endif // STYLEDWIDGET_H      
#include "styledwidget.h"
#include <QTime>
#include <QDebug>

StyledWidget::StyledWidget(QWidget *parent) : QWidget(parent)
{
    this->setMinimumSize(800,800);

    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(update()));//定时调用绘制事件函数
    timer->start(1000);//开启定时器,执行周期为1秒针
}

StyledWidget::~StyledWidget()
{

}

void StyledWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);//设置抗锯齿
    Draw_Clock(&painter);
}

void StyledWidget::Draw_Clock(QPainter *painter)
{
    Init_Parameter();
    Set_Mask(painter);

    Draw_Broad(painter);
    Draw_Dial(painter);
    Draw_Text(painter);
    Draw_Pointer(painter);
}

void StyledWidget::Init_Parameter()
{
    Center_pos = QPoint(this->width()/2,this->height()/2);//以窗体中心为圆心
    R_Edge = this->height()/2;//以窗体高度的一半为半径
    R_Inside = R_Edge-10;
    R_Center = 15;
    R_Pointer = 6;
    QTime Time = QTime::currentTime();//获取当前系统时间

    H=Time.hour();//分别设置时、分、秒
    M=Time.minute();
    S=Time.second();
}

void StyledWidget::Set_Mask(QPainter *painter)
{
    painter->save();//保存

    QBrush brush = QBrush(Qt::transparent);//设置画刷为透明
    painter->setBrush(brush);
    painter->fillRect(this->rect(),QColor(0,0,0,0));

    painter->restore();//恢复
}

void StyledWidget::Draw_Broad(QPainter *painter)
{
    painter->save();

    QBrush brush = QBrush(Color_Edge);//绘制外部圆
    painter->setBrush(brush);
    painter->drawEllipse(Center_pos,R_Edge,R_Edge);

    brush = QBrush(Color_Inside);//绘制内部圆
    painter->setBrush(brush);
    painter->drawEllipse(Center_pos,R_Inside,R_Inside);

    brush = QBrush(Color_Center);//绘制中心小圆
    painter->setBrush(brush);
    painter->drawEllipse(Center_pos,R_Center,R_Center);

    painter->restore();
}

void StyledWidget::Draw_Dial(QPainter *painter)
{
    painter->save();

    for(int Loop = 0; Loop <= Div_Max*Div_Min; Loop++)
    {
        float Angle = BaseAngle + (360 / (Div_Max * Div_Min))*Loop;//从基础仰角开始绘制的每条刻度线对应的角度
        int R = R_Inside-1;
        int x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
        int y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

        if(Loop % Div_Min == 0)//判断是否为大刻度
        {
            QPen pen(Qt::black);
            pen.setWidth(4);
            painter->setPen(pen);
            R = R_Inside-20;
        }
        else  //判断是否为小刻度
        {
            QPen pen(Qt::black);
            pen.setWidth(2);
            painter->setPen(pen);
            R = R_Inside-15;
        }

        int x_end = Center_pos.x() + R * cos((Angle / 180) * PI);
        int y_end = Center_pos.y() + R * sin((Angle / 180) * PI);

        painter->drawLine(QPoint(x_start,y_start),QPoint(x_end,y_end));//绘制刻度线
    }


    painter->restore();
}

void StyledWidget::Draw_Text(QPainter *painter)
{
    painter->save();

    QPen qPen(Qt::black);
    qPen.setWidth(5);   //设置画笔的粗细
    painter->setPen(qPen);
    QFont qFont("楷体",28,QFont::Bold,false);
    painter->setFont(qFont);

    int Dial_Text = 12;
    for(int Loop = 0;Loop < Div_Max;Loop++)
    {
        if(Dial_Text >12 )
            Dial_Text = 1;
        int R = R_Inside-60;
        float Angle = BaseAngle + (360 / Div_Max )*Loop;
        int x = Center_pos.x() + R * cos((Angle / 180) * PI);
        int y = Center_pos.y() + R * sin((Angle / 180) * PI);

        painter->drawText(QRect(x-20,y-20,80,80),QString::number(Dial_Text++));
    }
    painter->drawText(Center_pos.x()-60,Center_pos.y()+60,"劳力士");


    painter->restore();
}

void StyledWidget::Draw_Pointer(QPainter *painter)
{
    painter->save();

    QBrush qBrush = QBrush(QColor(Qt::black));
    painter->setBrush(qBrush);
    QPen qPen(Qt::black);
    qPen.setWidth(2);   //设置画笔的粗细
    painter->setPen(qPen);
//**********绘制秒针***********************************************************************************
    float Angle = BaseAngle + (360 / (Div_Max * Div_Min))*S;
    float RightAngle = Angle + 90;//右侧角度
    float LeftAngle = Angle - 90;//左侧角度
    int R = R_Inside-1;
    int x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
    int y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

    R = R_Pointer-1;
    int x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);//过圆心的右侧切点
    int y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
    int x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);//过圆心的左侧切点
    int y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);

    QPointF qTriangle_S[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
    painter->drawPolygon(qTriangle_S,3);
//**********绘制分针***********************************************************************************
    Angle = BaseAngle + (360 / (Div_Max * Div_Min))*M;
    RightAngle = Angle + 90;//右侧角度
    LeftAngle = Angle - 90;//左侧角度
    R = R_Inside-60;
    x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
    y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

    R = R_Pointer-1;
    x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);//过圆心的右侧切点
    y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
    x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);//过圆心的左侧切点
    y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);

    QPointF qTriangle_M[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
    painter->drawPolygon(qTriangle_M,3);
//**********绘制时针***********************************************************************************
    Angle = BaseAngle + (360 / Div_Max)*H;
    RightAngle = Angle + 90;//右侧角度
    LeftAngle = Angle - 90;//左侧角度
    R = R_Inside-120;
    x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
    y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

    R = R_Pointer-1;
    x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);//过圆心的右侧切点
    y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
    x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);//过圆心的左侧切点
    y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);

    QPointF qTriangle_H[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
    painter->drawPolygon(qTriangle_H,3);

    painter->restore();
}      

3.2、自定义类添加自定义属性及接口

//1、原先时钟控件中定义的成员变量(即属性)
private:
    QColor Color_Edge = QColor(0,0,0,255);//外部圆颜色
    QColor Color_Inside = QColor(255,255,255,255);//内部圆颜色
    QColor Color_Center = QColor(0,0,0,255);//中心小圆颜色

//2、添加属性接口
public:
    void set_Color_Edge(QColor color);
    QColor get_Color_Edge();

    void set_Color_Inside(QColor color);
    QColor get_Color_Inside();

    void set_Color_Center(QColor color);
    QColor get_Color_Center();
//=============================================对外接口==============================================
void StyledWidget::set_Color_Edge(QColor color)
{
    this->Color_Edge = color;
    this->update();
}
QColor StyledWidget::get_Color_Edge()
{
    return this->Color_Edge;
}

void StyledWidget::set_Color_Inside(QColor color)
{
    this->Color_Inside = color;
    this->update();
}
QColor StyledWidget::get_Color_Inside()
{
    return this->Color_Inside;
}

void StyledWidget::set_Color_Center(QColor color)
{
    this->Color_Center = color;
    this->update();
}
QColor StyledWidget::get_Color_Center()
{
    return this->Color_Center;
}

//3、添加Q_PROPERTY,暴露属性
Q_PROPERTY(QColor Color_Edge READ get_Color_Edge WRITE set_Color_Edge);
Q_PROPERTY(QColor Color_Inside READ get_Color_Inside WRITE set_Color_Inside);
Q_PROPERTY(QColor Color_Center READ get_Color_Center WRITE set_Color_Center);      

3.3、完整的时钟控件代码

#ifndef STYLEDWIDGET_H
#define STYLEDWIDGET_H

#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QtMath>
#include <QTimer>

#define PI 3.14

class StyledWidget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QColor Color_Edge READ get_Color_Edge WRITE set_Color_Edge);
    Q_PROPERTY(QColor Color_Inside READ get_Color_Inside WRITE set_Color_Inside);
    Q_PROPERTY(QColor Color_Center READ get_Color_Center WRITE set_Color_Center);
public:
    explicit StyledWidget(QWidget *parent = nullptr);
    ~StyledWidget();

public:
    void set_Color_Edge(QColor color);
    QColor get_Color_Edge();

    void set_Color_Inside(QColor color);
    QColor get_Color_Inside();

    void set_Color_Center(QColor color);
    QColor get_Color_Center();

protected:
    void paintEvent(QPaintEvent *);//重写绘制事件函数
    void Init_Parameter();//初始化参数函数
    void Set_Mask(QPainter *);//设置窗体透明
    void Draw_Clock(QPainter *);//绘制时钟
    void Draw_Broad(QPainter *);//绘制时钟盘
    void Draw_Dial(QPainter *);//绘制刻度盘
    void Draw_Text(QPainter *);//绘制刻度值
    void Draw_Pointer(QPainter *);//绘制指针

private:
    QTimer *timer;//定时器
    QPoint Center_pos;//时钟圆心坐标
    int R_Edge;//外部圆半径
    int R_Inside;//内部圆半径
    int R_Center;//中心小圆半径
    int R_Pointer;//中心指针圆半径
    int Div_Max = 12;//大刻度值
    int Div_Min = 5;//小刻度值
    float BaseAngle = 270;//基础仰角
    int H;//时
    int M;//分
    int S ;//秒

private:
    QColor Color_Edge = QColor(0,0,0,255);//外部圆颜色
    QColor Color_Inside = QColor(255,255,255,255);//内部圆颜色
    QColor Color_Center = QColor(0,0,0,255);//中心小圆颜色
};

#endif // STYLEDWIDGET_H      
#include "styledwidget.h"
#include <QTime>
#include <QDebug>

StyledWidget::StyledWidget(QWidget *parent) : QWidget(parent)
{
    this->setMinimumSize(800,800);

    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(update()));//定时调用绘制事件函数
    timer->start(1000);//开启定时器,执行周期为1秒针
}

StyledWidget::~StyledWidget()
{

}

void StyledWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);//设置抗锯齿
    Draw_Clock(&painter);
}

void StyledWidget::Draw_Clock(QPainter *painter)
{
    Init_Parameter();
    Set_Mask(painter);

    Draw_Broad(painter);
    Draw_Dial(painter);
    Draw_Text(painter);
    Draw_Pointer(painter);
}

void StyledWidget::Init_Parameter()
{
    Center_pos = QPoint(this->width()/2,this->height()/2);//以窗体中心为圆心
    R_Edge = this->height()/2;//以窗体高度的一半为半径
    R_Inside = R_Edge-10;
    R_Center = 15;
    R_Pointer = 6;
    QTime Time = QTime::currentTime();//获取当前系统时间

    H=Time.hour();//分别设置时、分、秒
    M=Time.minute();
    S=Time.second();
}

void StyledWidget::Set_Mask(QPainter *painter)
{
    painter->save();//保存

    QBrush brush = QBrush(Qt::transparent);//设置画刷为透明
    painter->setBrush(brush);
    painter->fillRect(this->rect(),QColor(0,0,0,0));

    painter->restore();//恢复
}

void StyledWidget::Draw_Broad(QPainter *painter)
{
    painter->save();

    QBrush brush = QBrush(Color_Edge);//绘制外部圆
    painter->setBrush(brush);
    painter->drawEllipse(Center_pos,R_Edge,R_Edge);

    brush = QBrush(Color_Inside);//绘制内部圆
    painter->setBrush(brush);
    painter->drawEllipse(Center_pos,R_Inside,R_Inside);

    brush = QBrush(Color_Center);//绘制中心小圆
    painter->setBrush(brush);
    painter->drawEllipse(Center_pos,R_Center,R_Center);

    painter->restore();
}

void StyledWidget::Draw_Dial(QPainter *painter)
{
    painter->save();

    for(int Loop = 0; Loop <= Div_Max*Div_Min; Loop++)
    {
        float Angle = BaseAngle + (360 / (Div_Max * Div_Min))*Loop;//从基础仰角开始绘制的每条刻度线对应的角度
        int R = R_Inside-1;
        int x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
        int y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

        if(Loop % Div_Min == 0)//判断是否为大刻度
        {
            QPen pen(Qt::black);
            pen.setWidth(4);
            painter->setPen(pen);
            R = R_Inside-20;
        }
        else  //判断是否为小刻度
        {
            QPen pen(Qt::black);
            pen.setWidth(2);
            painter->setPen(pen);
            R = R_Inside-15;
        }

        int x_end = Center_pos.x() + R * cos((Angle / 180) * PI);
        int y_end = Center_pos.y() + R * sin((Angle / 180) * PI);

        painter->drawLine(QPoint(x_start,y_start),QPoint(x_end,y_end));//绘制刻度线
    }


    painter->restore();
}

void StyledWidget::Draw_Text(QPainter *painter)
{
    painter->save();

    QPen qPen(Qt::black);
    qPen.setWidth(5);   //设置画笔的粗细
    painter->setPen(qPen);
    QFont qFont("楷体",28,QFont::Bold,false);
    painter->setFont(qFont);

    int Dial_Text = 12;
    for(int Loop = 0;Loop < Div_Max;Loop++)
    {
        if(Dial_Text >12 )
            Dial_Text = 1;
        int R = R_Inside-60;
        float Angle = BaseAngle + (360 / Div_Max )*Loop;
        int x = Center_pos.x() + R * cos((Angle / 180) * PI);
        int y = Center_pos.y() + R * sin((Angle / 180) * PI);

        painter->drawText(QRect(x-20,y-20,80,80),QString::number(Dial_Text++));
    }
    painter->drawText(Center_pos.x()-60,Center_pos.y()+60,"劳力士");


    painter->restore();
}

void StyledWidget::Draw_Pointer(QPainter *painter)
{
    painter->save();

    QBrush qBrush = QBrush(QColor(Qt::black));
    painter->setBrush(qBrush);
    QPen qPen(Qt::black);
    qPen.setWidth(2);   //设置画笔的粗细
    painter->setPen(qPen);
//**********绘制秒针***********************************************************************************
    float Angle = BaseAngle + (360 / (Div_Max * Div_Min))*S;
    float RightAngle = Angle + 90;//右侧角度
    float LeftAngle = Angle - 90;//左侧角度
    int R = R_Inside-1;
    int x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
    int y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

    R = R_Pointer-1;
    int x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);//过圆心的右侧切点
    int y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
    int x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);//过圆心的左侧切点
    int y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);

    QPointF qTriangle_S[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
    painter->drawPolygon(qTriangle_S,3);
//**********绘制分针***********************************************************************************
    Angle = BaseAngle + (360 / (Div_Max * Div_Min))*M;
    RightAngle = Angle + 90;//右侧角度
    LeftAngle = Angle - 90;//左侧角度
    R = R_Inside-60;
    x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
    y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

    R = R_Pointer-1;
    x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);//过圆心的右侧切点
    y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
    x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);//过圆心的左侧切点
    y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);

    QPointF qTriangle_M[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
    painter->drawPolygon(qTriangle_M,3);
//**********绘制时针***********************************************************************************
    Angle = BaseAngle + (360 / Div_Max)*H;
    RightAngle = Angle + 90;//右侧角度
    LeftAngle = Angle - 90;//左侧角度
    R = R_Inside-120;
    x_start = Center_pos.x() + R * cos((Angle / 180) * PI);
    y_start = Center_pos.y() + R * sin((Angle / 180) * PI);

    R = R_Pointer-1;
    x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);//过圆心的右侧切点
    y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
    x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);//过圆心的左侧切点
    y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);

    QPointF qTriangle_H[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
    painter->drawPolygon(qTriangle_H,3);

    painter->restore();
}

//=============================================对外接口==============================================
void StyledWidget::set_Color_Edge(QColor color)
{
    this->Color_Edge = color;
    this->update();
}
QColor StyledWidget::get_Color_Edge()
{
    return this->Color_Edge;
}

void StyledWidget::set_Color_Inside(QColor color)
{
    this->Color_Inside = color;
    this->update();
}
QColor StyledWidget::get_Color_Inside()
{
    return this->Color_Inside;
}

void StyledWidget::set_Color_Center(QColor color)
{
    this->Color_Center = color;
    this->update();
}
QColor StyledWidget::get_Color_Center()
{
    return this->Color_Center;
}      

3.4、添加qss文件

不懂怎么使用qss文件的可以参考:​​学习QT之QSS的使用​​

新建qss文件,在其内添加qss代码,QSS中使用自定义的属性设置样式需要使用​

​qproperty-属性​

​的形式;

为了查看效果,我新建了三个qss文件:

【qss1.qss】

StyledWidget {
    qproperty-Color_Edge: black;
    qproperty-Color_Inside: white;
    qproperty-Color_Center: black;
}      

【qss2.qss】

StyledWidget {
    qproperty-Color_Edge: #FF8247;
    qproperty-Color_Inside: #FFC1C1;
    qproperty-Color_Center: #FF6A6A;
}      

【qss3.qss】

StyledWidget {
    qproperty-Color_Edge: #00FF00;
    qproperty-Color_Inside: #00FF7F;
    qproperty-Color_Center: #FFFACD;
}      

3.5、切换qss

void MainWindow::Set_QSS(QString qssPath)//设置样式
{
    QFile file(qssPath);
    file.open(QFile::ReadOnly);
    QString styleSheet = tr(file.readAll());
    this->setStyleSheet(styleSheet);
    file.close();
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if(event->key()==Qt::Key_A) {
        qDebug()<<"Key_A";

        Set_QSS(":/QSS/Resources/qss1.qss");
    }
    if(event->key()==Qt::Key_B) {
        qDebug()<<"Key_B";

        Set_QSS(":/QSS/Resources/qss2.qss");
    }
    if(event->key()==Qt::Key_C) {
        qDebug()<<"Key_C";

        Set_QSS(":/QSS/Resources/qss3.qss");
    }
}      

四、工程分享