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


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