天天看點

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");
    }
}      

四、工程分享