QT中窗口自绘制效果展示

项目中需要使用QT进行窗口自绘,前期先做一下技术探索,参考相关资料代码熟悉流程。本着代码是最好的老师原则,在此记录一下。

目录

1.运行效果

2.代码结构

3.具体代码


1.运行效果

QT中窗口自绘制效果展示_第1张图片

2.代码结构

QT中窗口自绘制效果展示_第2张图片

3.具体代码

myspeed.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    drawdialog.cpp \
    main.cpp \
    meter1.cpp \
    meter2.cpp

HEADERS += \
    drawdialog.h \
    meter1.h \
    meter2.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

drawdialog.h

#include 

class DrawDialog : public QDialog
{
     Q_OBJECT

public:
     explicit DrawDialog(QWidget *parent = 0);
     void mousePressEvent(QMouseEvent *event);
     void mouseMoveEvent(QMouseEvent *event);
     void paintEvent(QPaintEvent *event) ;
     void keyPressEvent( QKeyEvent * event );
private:
     QPoint m_CurrentPos;
};

meter1.h

#ifndef METER1_H
#define METER1_H

#include 
#include 

// 仪表盘开发参考博客
// https://blog.csdn.net/yyz_1987/article/details/126958420#comments_29151980
class MyMeter1 : public QWidget
{
    Q_OBJECT

public:
    MyMeter1(QWidget *parent = 0);
    ~MyMeter1();

    void setValue(double val);

protected:
    void paintEvent(QPaintEvent *);

    void drawCrown(QPainter *painter);
    void drawBackground(QPainter *painter);
    void drawScale(QPainter *painter);
    void drawScaleNum(QPainter *painter);
    void drawTitle(QPainter *painter);
    void drawIndicator(QPainter *painter);
    void drawNumericValue(QPainter *painter);

protected:
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

private:
    QPoint mousePoint;
    bool mouse_press;

private:
    QColor m_background;
    QColor m_foreground;


    int m_maxValue;
    int m_minValue;
    int m_startAngle;
    int m_endAngle;

    int m_scaleMajor;
    int m_scaleMinor;
    double m_value;
    int m_precision;
    QTimer *m_updateTimer;
    QString m_units;
    QString m_title;

public Q_SLOTS:
    void UpdateAngle();

private:

};

#endif // METER1_H

meter2.h

#ifndef METER2_H
#define METER2_H

#include 

class MyMeter2 : public QWidget
{
    Q_OBJECT

public:
    MyMeter2(QWidget *parent = nullptr);
    ~MyMeter2();

    void paintEvent(QPaintEvent *event);
    void timerEvent(QTimerEvent *e);

private:
    void drawFrame(QPainter *painter);
    void drawScale(QPainter *painter);
    void drawScaleNum(QPainter *painter);

    void drawPointer(QPainter *painter);
    void drawSpeed(QPainter *painter);

    void drawUnit(QPainter *painter);


    int speed;
    int time_id;
    int status;
    qreal m_angle;
    QColor m_foreground;

    int m_maxValue;
    int m_minValue;
    int m_startAngle;
    int m_endAngle;

    int m_scaleMajor;
    int m_scaleMinor;
    double m_value;
    int m_precision;
    //QTimer *m_updateTimer;
    QString m_units;
    QString m_title;

};
#endif // METER2_H

drawdialog.cpp

#include "drawdialog.h"
#include 
#include 
#include 

DrawDialog::DrawDialog(QWidget *parent) : QDialog(parent)
 {
     //让程序无边框
     setWindowFlags( Qt::FramelessWindowHint );
     //让程序背景透明
     setAttribute(Qt::WA_TranslucentBackground, true);
}

void DrawDialog::mousePressEvent(QMouseEvent *event)
{
     //当鼠标左键按下时,记录当前位置
     if(event->button() == Qt::LeftButton)
     {
         m_CurrentPos = event->globalPos() - frameGeometry().topLeft();
         event->accept();
     }
      QDialog::mousePressEvent(event);
}

void DrawDialog::mouseMoveEvent(QMouseEvent *event)
{
     //支持窗体移动
     if (event->buttons() & Qt::LeftButton)
      {
         move(event->globalPos() - m_CurrentPos);
         event->accept();
     }

     QDialog::mouseMoveEvent(event);
    }

  //绘制图形
 void DrawDialog::paintEvent(QPaintEvent *event)
 {
      QPainter painter(this);
      //反走样
      painter.setRenderHint(QPainter::Antialiasing,true);

     painter.setPen( QPen(Qt::green, 2) );
     painter.setBrush( Qt::blue );
     QRect rect(10,10,200,260);
     //绘制一个椭圆
     painter.drawEllipse(rect);
 }

void DrawDialog::keyPressEvent( QKeyEvent * event )
{
      //按下esc键时,关闭
      if(event->key() == Qt::Key_Escape)
      {
          close();
      }
}

meter1.cpp

#include "meter1.h"

#include 

// 构造函数
MyMeter1::MyMeter1(QWidget *parent){

    m_background = Qt::black;
    m_foreground = Qt::white;

    m_startAngle = 60;
    m_endAngle = 60;
    m_scaleMajor = 10;
    m_minValue = 0;
    m_maxValue = 100;
    m_scaleMajor = 10;//分度
    m_scaleMinor = 10;
    m_units = "L/min";
    m_title = "仪表盘";
    m_precision = 0;
    m_value = 0;
    mouse_press = false;

    setWindowFlags(Qt::FramelessWindowHint);//无窗体
    setAttribute(Qt::WA_TranslucentBackground);//背景透明
    resize(500, 500);

}

MyMeter1::~MyMeter1()
{

}

void MyMeter1::setValue(double val)
{
    m_value = val;
}
//绘制表冠
void MyMeter1::drawCrown(QPainter *painter)
{
    painter->save();
    int radius = 100;
    QLinearGradient lg1(0, -radius, 0, radius);

    lg1.setColorAt(0, Qt::white); //设置渐变的颜色和路径比例
    lg1.setColorAt(1, Qt::gray); //只是粗略的颜色,具体的可以参考RGB颜色查询对照表

    painter->setBrush(lg1); // 创建QBrush对象,把这个渐变对象传递进去:
    painter->setPen(Qt::NoPen); //边框线无色
    painter->drawEllipse(-radius, -radius, radius << 1, radius << 1);
    painter->setBrush(m_background = Qt::black);
    painter->drawEllipse(-92, -92, 184, 184);
    painter->restore();
}

 //绘制刻度数字
void MyMeter1::drawScaleNum(QPainter *painter)
{
    painter->save();
    painter->setPen(m_foreground);
    //m_startAngle是起始角度,m_endAngle是结束角度,m_scaleMajor在一个量程中分成的刻度数
    double startRad = ( 270-m_startAngle) * (3.14 / 180);
    double deltaRad = (360 - m_startAngle - m_endAngle) * (3.14 / 180) / m_scaleMajor;
    double sina,cosa;
    int x, y;
    QFontMetricsF fm(this->font());
    double w, h, tmpVal;
    QString str;

    for (int i = 0; i <= m_scaleMajor; i++)
    {
        sina = sin(startRad - i * deltaRad);
        cosa = cos(startRad - i * deltaRad);

       tmpVal = 1.0 * i *((m_maxValue - m_minValue) / m_scaleMajor) + m_minValue;
       // tmpVal = 50;
        str = QString( "%1" ).arg(tmpVal);  //%1作为占位符   arg()函数比起 sprintf()来是类型安全的
        w = fm.size(Qt::TextSingleLine,str).width();
        h = fm.size(Qt::TextSingleLine,str).height();
        x = 82 * cosa - w / 2;
        y = -82 * sina + h / 4;
        painter->drawText(x, y, str); //函数的前两个参数是显示的坐标位置,后一个是显示的内容,是字符类型""

    }
    painter->restore();
}

// 绘制刻度线
void MyMeter1::drawScale(QPainter *painter) //绘制刻度线
{
    painter->save();
    painter->rotate(m_startAngle);
    int steps = (m_scaleMajor * m_scaleMinor); //相乘后的值是分的份数
    double angleStep = (360.0 - m_startAngle - m_endAngle) / steps; //每一个份数的角度

    // painter->setPen(m_foreground); //m_foreground是颜色的设置
    // QPen pen = painter->pen(); //第一种方法
    QPen pen ;
    pen.setColor(Qt::green); //推荐使用第二种方式
    for (int i = 0; i <= steps; i++)
    {
    if (i % m_scaleMinor == 0)//整数刻度显示加粗
    {
    pen.setWidth(1); //设置线宽
    painter->setPen(pen); //使用面向对象的思想,把画笔关联上画家。通过画家画出来

      painter->drawLine(0, 62, 0, 72); //两个参数应该是两个坐标值
       }
       else
       {
           pen.setWidth(0);
           painter->setPen(pen);
           painter->drawLine(0, 67, 0, 72);
       }
       painter->rotate(angleStep);
    }
    painter->restore();
}

void MyMeter1::drawTitle(QPainter *painter)
{
    painter->save();
    painter->setPen(m_foreground);
    //painter->setBrush(m_foreground);
    QString str(m_title); //显示仪表的功能
    QFontMetricsF fm(this->font());
    double w = fm.size(Qt::TextSingleLine,str).width();
    painter->drawText(-w / 2, -30, str);
    painter->restore();
}

// 显示的单位,与数值
void MyMeter1::drawNumericValue(QPainter *painter)
{
    QString str = QString("%1 %2").arg(m_value, 0, 'f', m_precision).arg(m_units);
    QFontMetricsF fm(font());
    double w = fm.size(Qt::TextSingleLine,str).width();
    painter->setPen(m_foreground);
    painter->drawText(-w / 2, 42, str);
}

void MyMeter1::UpdateAngle()
{
    update();
}

// 绘制表针,和中心点
void MyMeter1::drawIndicator(QPainter *painter)
{
    painter->save();
    QPolygon pts;
    pts.setPoints(3, -2, 0, 2, 0, 0, 60);	/* (-2,0)/(2,0)/(0,60) *///第一个参数是 ,坐标的个数。后边的是坐标

    painter->rotate(m_startAngle);
    double degRotate = (360.0 - m_startAngle - m_endAngle) / (m_maxValue - m_minValue)*(m_value - m_minValue);

    //画指针
    painter->rotate(degRotate);  //顺时针旋转坐标系统
    QRadialGradient haloGradient(0, 0, 60, 0, 0);  //辐射渐变
    haloGradient.setColorAt(0, QColor(60, 60, 60));
    haloGradient.setColorAt(1, QColor(160, 160, 160)); //灰
    painter->setPen(Qt::white); //定义线条文本颜色  设置线条的颜色
    painter->setBrush(haloGradient);//刷子定义形状如何填满 填充后的颜色
    painter->drawConvexPolygon(pts); //这是个重载函数,绘制多边形。
    painter->restore();

    //画中心点
    QColor niceBlue(150, 150, 200);
    QConicalGradient coneGradient(0, 0, -90.0);  //角度渐变
    coneGradient.setColorAt(0.0, Qt::darkGray);
    coneGradient.setColorAt(0.2, niceBlue);
    coneGradient.setColorAt(0.5, Qt::white);
    coneGradient.setColorAt(1.0, Qt::darkGray);
    painter->setPen(Qt::NoPen);  //没有线,填满没有边界
    painter->setBrush(coneGradient);
    painter->drawEllipse(-5, -5, 10, 10);
}

// 重绘函数
void MyMeter1 ::paintEvent(QPaintEvent *)
{

    int width=this->width();
    int height=this->height();

    QPainter painter(this);//一个类中的this表示一个指向该类自己的指针

    painter.setRenderHint(QPainter::Antialiasing);  /* 使用反锯齿(如果可用) */
    painter.translate(width/2, height/2);   /* 坐标变换为窗体中心 */
    int side = qMin(width, height);
    painter.scale(side / 200.0, side / 200.0);      /* 比例缩放 */

   drawCrown(&painter);                                 /* 画表盘边框 */
   drawScaleNum(&painter);                          /* 画刻度数值值 */
   drawScale(&painter);                                 /* 画刻度线 */
   drawTitle(&painter);                                 /* 画单位 */
   drawNumericValue(&painter);                      /* 画数字显示 */
   drawIndicator(&painter);                             /* 画表针 */

}

void MyMeter1::mousePressEvent(QMouseEvent *event)
 {

      if( (event->button() == Qt::LeftButton) ){
          mouse_press = true;
         mousePoint = event->globalPos() - this->pos();
 //        event->accept();
      }
    else if(event->button() == Qt::RightButton){
       //如果是右键
        this->close();

     }
}

void MyMeter1::mouseMoveEvent(QMouseEvent *event)
{


//    if(event->buttons() == Qt::LeftButton){  //如果这里写这行代码,拖动会有点问题
     if(mouse_press){
         move(event->globalPos() - mousePoint);
//        event->accept();
     }
}

void MyMeter1::mouseReleaseEvent(QMouseEvent *event)
{
    mouse_press = false;
}

meter2.cpp

#include "meter2.h"

#include 
#include 
#include 
#include 
#include 
#include 

#include 

MyMeter2::MyMeter2(QWidget *parent)
    : QWidget(parent)
{
    //resize(800, 480);
    //setWindowTitle("test");

    m_foreground = Qt::red;//Qt::black;

    speed = 0;
    status = 0;

    m_startAngle = 45;
    m_endAngle = 45;

    m_minValue = 0;
    m_maxValue = 100;

    m_scaleMajor = 10;//分度
    m_scaleMinor = 10;
    m_units = "KM/H";
    m_title = "My Speed";
    m_precision = 0;
    m_value = 0;

    m_angle = (qreal)270/(m_maxValue-1);
    //setWindowFlags(Qt::FramelessWindowHint);//无窗体
    //setAttribute(Qt::WA_TranslucentBackground);//背景透明
    time_id = this->startTimer(50);
}

MyMeter2::~MyMeter2()
{
}

void MyMeter2::paintEvent(QPaintEvent *event)
{
    int width=this->width();
    int height=this->height();


    QPainter painter(this);

    painter.translate(width/2, height/2);

    int side = qMin(width, height);
    painter.scale(side / 200.0, side / 200.0);      /* 比例缩放 */

    drawFrame(&painter);

    drawScale(&painter);                                 /* 画刻度线 */

    drawScaleNum(&painter);                          /* 画刻度数值值 */
    drawUnit(&painter);
    drawPointer(&painter);

    drawSpeed(&painter);
}

void MyMeter2::drawFrame(QPainter *painter)
{
    painter->save();
    // 半径100
    int radius = 100;

    painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));
    painter->drawArc(-radius, -radius, radius<<1, radius<<1, -135*16, -270*16);

    painter->restore();

}

// 绘制刻度线
void MyMeter2::drawScale(QPainter *painter)
{

    painter->save();
    painter->rotate(m_startAngle);
    int steps = (m_scaleMajor * m_scaleMinor); //相乘后的值是分的份数
    double angleStep = (360.0 - m_startAngle - m_endAngle) / steps; //每一个份数的角度

    // painter->setPen(m_foreground); //m_foreground是颜色的设置
    // QPen pen = painter->pen(); //第一种方法
    QPen pen ;
    pen.setColor(m_foreground); //推荐使用第二种方式
    for (int i = 0; i <= steps; i++)
    {
        if (i % m_scaleMinor == 0)//整数刻度显示加粗
        {
            pen.setWidth(1); //设置线宽
            painter->setPen(pen); //使用面向对象的思想,把画笔关联上画家。通过画家画出来

            painter->drawLine(0, 90, 0, 100); //两个参数应该是两个坐标值
        }
        else
        {
           pen.setWidth(0);
           painter->setPen(pen);
           painter->drawLine(0, 95, 0, 100);
        }
       painter->rotate(angleStep);
    }
    painter->restore();
}
// 绘制刻度
void MyMeter2::drawScaleNum(QPainter *painter)
{
    painter->save();
    painter->setPen(m_foreground);
    //m_startAngle是起始角度,m_endAngle是结束角度,m_scaleMajor在一个量程中分成的刻度数
    double startRad = ( 270-m_startAngle) * (3.14 / 180);
    double deltaRad = (360 - m_startAngle - m_endAngle) * (3.14 / 180) / m_scaleMajor;
    double sina,cosa;
    int x, y;
    QFontMetricsF fm(this->font());
    double w, h, tmpVal;
    QString str;

    for (int i = 0; i <= m_scaleMajor; i++)
    {
        sina = sin(startRad - i * deltaRad);
        cosa = cos(startRad - i * deltaRad);

       tmpVal = 1.0 * i *((m_maxValue - m_minValue) / m_scaleMajor) + m_minValue;
       // tmpVal = 50;
        str = QString( "%1" ).arg(tmpVal);  //%1作为占位符   arg()函数比起 sprintf()来是类型安全的
        w = fm.size(Qt::TextSingleLine,str).width();
        h = fm.size(Qt::TextSingleLine,str).height();
        x = 82 * cosa - w / 2;
        y = -82 * sina + h / 4;
        painter->drawText(x, y, str); //函数的前两个参数是显示的坐标位置,后一个是显示的内容,是字符类型""

    }
    painter->restore();
}

void MyMeter2::drawPointer(QPainter *painter)
{
    int radius = 100;
    QPoint point[4] = {
        QPoint(0, 10),
        QPoint(-10, 0),
        QPoint(0, -80),
        QPoint(10, 0),
    };

    painter->save();

    QLinearGradient linear;
    linear.setStart(-radius, -radius);
    linear.setFinalStop(radius<<1, radius<<1);
    linear.setColorAt(0, QColor(0, 255, 255, 0));
    linear.setColorAt(1, QColor(0, 255, 255, 255));
    painter->setPen(Qt::NoPen);
    painter->setBrush(linear);
    painter->drawPie(-radius, -radius, radius<<1, radius<<1, 225 * 16, -(m_angle * this->speed) * 16);

    painter->restore();

    painter->save();

    painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));
    painter->rotate(-135 + this->speed * m_angle);
    painter->drawPolygon(point, 4);

    painter->restore();
}

void MyMeter2::drawSpeed(QPainter *painter)
{
    painter->save();

    painter->setPen(QColor("#0"));
    //  绘制速度
    QFont font("Times", 10, QFont::Bold);
    font.setBold(true);
    font.setPixelSize(46);
    painter->setFont(font);
    painter->drawText(-60, 0, 120, 92, Qt::AlignCenter, QString::number(speed));
    painter->restore();
}

void MyMeter2::drawUnit(QPainter *painter)
{
    QString str = QString("%1").arg(m_units);
    QFontMetricsF fm(font());
    double w = fm.size(Qt::TextSingleLine,str).width();
    painter->setPen(m_foreground);
    painter->drawText(-w / 2, 82, str);
}

void MyMeter2::timerEvent(QTimerEvent *e)
{
    int timerId = e->timerId();

    if(this->time_id == timerId) {
        if(this->status == 0) {
            this->speed += 1;
            if(this->speed >= m_maxValue)
                this->status = 1;
        }else {
            this->speed -= 1;
            if(this->speed <= 0)
                this->status = 0;

        }

        this->update();
    }
}

main.cpp

#include "mainwindow.h"
#include "meter1.h"
#include "meter2.h"
#include "drawdialog.h"
#include 

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

    MyMeter1 w1;
    w1.setValue(33.12);
    w1.show();

    MyMeter2 w2;
    w2.show();

    DrawDialog w3;
    w3.show();

    return a.exec();
}

你可能感兴趣的:(QT,qt)