文章目錄
- 一、前言
- 二、效果展示
- 三、具體步驟
- 3.1、自定義繼承自QWidget的類
- 3.2、自定義類添加自定義屬性及接口
- 3.3、完整的時鐘控件代碼
- 3.4、添加qss檔案
- 3.5、切換qss
- 四、工程分享
一、前言
在Qt中,我們可以使用QSS來定制軟體的樣式,QSS提供了各種【選擇器】、【屬性】、【僞狀态】等來幫助我們實作這一目的,但是似乎這些都是針對Qt提供的内部類,由于一些特定的需求,我們有些時候需要自定義控件,那自定義的控件不是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");
}
}