1、简介

最近学习了一下QT,熟悉了一段时间后发现它的功能还是挺强大的,同时也比较方便用户上手去使用。现在就基于最近学习的内容,实现一个简易的带指针旋转功能的表盘。文中表盘的实现是基于QT的QPainter类中的绘图方法,同时外加QT的定时器设计完成的。效果上肯定没有贴图片那么美观,不过两者的设计思想是基本一样的,这里的设计方法可以提供给你一个不错的参考。

2、设计思路

在讲解设计思路前还是先来看下绘制的表盘所实现的效果吧!后面对实现效果进行一步步拆解来讲解,这样或许会更加直观,更便于理解。

我们先不去考虑指针旋转这一动态过程实现,可以将表盘分解析为3个组成部分,表盘的外形轮廓、指针和显示的当前速度的数值。外形轮廓由一个圆弧和一些指示刻度组成,它的绘制肯定要使用QT中的画圆弧的函数、画线函数还有显示文本函数。指针是一个不规则的多边形,它的绘制会用到QT中的绘制多边形的函数。显示当前速度值比较简单些,直接使用显示文本函数绘制。

有了静态部分的基础,现在开始考虑指针的动态旋转过程和旋转过程中的渐变效果是如何实现的。指针旋转的角度应该和当前的转速相互对应,当前转速改变时,会根据新的转速计算出当前指针位于什么角度的位置,然后可以调用QT的旋转角度函数让多边形指针旋转到这个位置。旋转的渐变效果其实是通过绘制扇形实现的,要绘制扇形的角度和指针旋转的角度是一样,由于绘制的扇形的内部的着色采用了颜色的线性内插,所以不同的角度显示的颜色程度不同,因此给人以渐变的效果。

转速的周期改变是在定时器中完成的,构造函数中初始化一个周期定时器,当定时器时间超时,根据当前转速的状态(上行还是下行),确定让转速自增1还是自减1。转速改变时,调用函数让界面进行重新绘制。

3、核心函数

所用到的绘制函数都是QPainter类中的方法, QPainter可以理解成是个画家,这个画家有很多种绘制图形的方法,它可以在所以继承QPaintDevice的类上进行绘制。

绘制多边形:

  drawPolygon

QT中drawPolygon有很多重载版本,要传入的参数一般就是要指定绘制多边形的所有顶点位置。

绘制圆弧:

  drawArc

同理,QT中也有很多drawArc的重载版本。它传入的参数比较特殊,QT中的绘制圆弧是在一个正方形中操作的,要传入的是正方形区域的大小,绘制圆弧的圆心默认是在传入正方形区域中心。除此之外还需要指定要绘制圆弧的起始角度和跨越的角度,它传入是值是实际角度*16。 当传入的角度值为正,表示逆时针绘制圆弧,角度值为负,表示顺时钟绘制圆弧。

绘制扇形:

  drawPie

绘制扇形和绘制圆弧的参数类似,可参考绘制圆弧。

QPainter坐标转换:

  translate

如执行painter.translate(100, 100),后续绘制的参考坐标变成了相对100, 100位置而言的。执行painter.drawLine(0, 0, 0, 20),实际绘制直线的两端点是(100, 100)和(100, 120)

旋转:

  ratate

坐标转换和旋转过程可参考下图:

保存和恢复QPainter状态:

  save

  restore

save保存当前QPainter状态(即当前对QPainter的设置)到堆栈,restore恢复之前保存的状态。这两个方法在QPainter绘图中很有用,详细可参考后面代码。

4、代码实现

先从定时器函数函数来看,当构造函数中设置的定时器超时,会产生定时器事件,timerEvent被自动调用

void Widget::timerEvent(QTimerEvent *e)
{
int timerId = e->timerId(); if(this->time_id == timerId) {
if(this->status == 0) {
this->speed += 1;
if(this->speed >= 180)
this->status = 1;
}else {
this->speed -= 1;
if(this->speed <= 0)
this->status = 0; } this->update();
}
}

判断当前转速是处于上行还是下行状态,根据转速所处的状态修改转速。然后调用this->update(), 该函数会产生Widget类中的重绘事件,paintEvent函数被执行。

painteEvent函数内容如下:

void Widget::paintEvent(QPaintEvent *event)
{
qreal angle; angle = (qreal)270 / (180-1); QPainter painter(this); painter.translate(width()/2, height()/2); drawFrame(&painter, angle); //① drawPointer(&painter, angle); //② drawSpeed(&painter); //③
}

① 绘制仪表盘圆弧形状的外框

② 根据转速大小,计算当前指针所在的角度,然后绘制指针和产生渐变效果的扇形

③ 显示当前转速值

drawFrame函数

void Widget::drawFrame(QPainter *painter, qreal angle)
{
painter->save(); painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));
painter->drawArc(-200, -200, 400, 400, -135*16, -270*16); //① painter->restore(); for(int i = 0; i < 180; i++) { //②
painter->save(); painter->rotate(-225 + i * angle); if(i % 10 == 0) {
painter->drawLine(180, 0, 200, 0);
}else {
painter->drawLine(190, 0, 200, 0);
} painter->restore();
} painter->save(); for(int i = 0; i < 9; i++) { //③ int xTextPos = 180 * qCos((225 - i * 15)*3.14/180);
int yTextPos = -180 * qSin((225 - i * 15)*3.14/180);
painter->drawText(xTextPos+5, yTextPos+10, QString::number(i * 10));
painter->drawText(-xTextPos-25, yTextPos+10, QString::number((18 - i) * 10));
}
painter->drawText(-10, -165, "90"); painter->restore();
}

① 绘制表盘的外形圆弧

② 绘制圆弧上的刻度信息

③ 绘制表盘外形的刻度旁边的数值,这里利用了圆的对称性

drawPointer函数

void Widget::drawPointer(QPainter *painter, qreal angle)
{
QPoint point[4] = {
QPoint(0, 10),
QPoint(-10, 0),
QPoint(0, -170),
QPoint(10, 0),
}; painter->save(); QLinearGradient linear; //①
linear.setStart(-200, -200);
linear.setFinalStop(200, 200);
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(-200, -200, 400, 400, 225 * 16, -(angle * this->speed) * 16); painter->restore(); painter->save(); painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));
painter->rotate(-135 + this->speed * angle);
painter->drawPolygon(point, 4); //② painter->restore();
}

① 根据当前速度计算扇形区域的大小,绘制渐变扇形

② 根据当前速度计算指针所要在的位置,旋转指针到该位置

drawSpeed函数

void Widget::drawSpeed(QPainter *painter)
{
painter->save(); painter->setPen(QColor("#0"));
// 绘制速度
QFont font("Times", 10, QFont::Bold);
font.setBold(true);
font.setPixelSize(66);
painter->setFont(font);
painter->drawText(-60, 100, 120, 92, Qt::AlignCenter, QString::number(speed));
painter->restore();
}

drawSpeed函数在指定位置,使用指定颜色字体,显示当前速度

5、小结

到此,模拟仪表盘的实现讲解完毕了,这也算对这几天QT的学习做了一个小小的总结。从使用过程中可以感受到使用QT进行图形界面的设计,软件编写上还是比较灵活的。QT的GUI功能非常很强大,它提供的接口函数很多,但想要都用好的确很难,平时还需要多看看QT官方文档中的解释和提供的demo。

完整代码

#include "widget.h"

#include <QPainter>
#include <QBrush>
#include <QLabel>
#include <QTimerEvent>
#include <QLinearGradient>
#include <QFont> #include <QtMath> Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(800, 480);
setWindowTitle("模拟仪表盘"); this->speed = 0;
this->status = 0; this->time_id = this->startTimer(50);
} Widget::~Widget()
{
} void Widget::paintEvent(QPaintEvent *event)
{
qreal angle; angle = (qreal)270 / (180-1); QPainter painter(this); painter.translate(width()/2, height()/2); drawFrame(&painter, angle); drawPointer(&painter, angle); drawSpeed(&painter);
} void Widget::drawFrame(QPainter *painter, qreal angle)
{
painter->save(); painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));
painter->drawArc(-200, -200, 400, 400, -135*16, -270*16); painter->restore(); for(int i = 0; i < 180; i++) {
painter->save(); painter->rotate(-225 + i * angle); if(i % 10 == 0) {
painter->drawLine(180, 0, 200, 0);
}else {
painter->drawLine(190, 0, 200, 0);
} painter->restore();
} painter->save(); for(int i = 0; i < 9; i++) { int xTextPos = 180 * qCos((225 - i * 15)*3.14/180);
int yTextPos = -180 * qSin((225 - i * 15)*3.14/180);
painter->drawText(xTextPos+5, yTextPos+10, QString::number(i * 10));
painter->drawText(-xTextPos-25, yTextPos+10, QString::number((18 - i) * 10));
}
painter->drawText(-10, -165, "90"); painter->restore();
} void Widget::drawPointer(QPainter *painter, qreal angle)
{
QPoint point[4] = {
QPoint(0, 10),
QPoint(-10, 0),
QPoint(0, -170),
QPoint(10, 0),
}; painter->save(); QLinearGradient linear;
linear.setStart(-200, -200);
linear.setFinalStop(200, 200);
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(-200, -200, 400, 400, 225 * 16, -(angle * this->speed) * 16); painter->restore(); painter->save(); painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));
painter->rotate(-135 + this->speed * angle);
painter->drawPolygon(point, 4); painter->restore();
} void Widget::drawSpeed(QPainter *painter)
{
painter->save(); painter->setPen(QColor("#0"));
// 绘制速度
QFont font("Times", 10, QFont::Bold);
font.setBold(true);
font.setPixelSize(66);
painter->setFont(font);
painter->drawText(-60, 100, 120, 92, Qt::AlignCenter, QString::number(speed));
painter->restore();
} void Widget::timerEvent(QTimerEvent *e)
{
int timerId = e->timerId(); if(this->time_id == timerId) {
if(this->status == 0) {
this->speed += 1;
if(this->speed >= 180)
this->status = 1;
}else {
this->speed -= 1;
if(this->speed <= 0)
this->status = 0; } this->update();
}
}

widget.cpp

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget> class Widget : public QWidget
{
Q_OBJECT public:
Widget(QWidget *parent = nullptr);
~Widget(); void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *e); private:
void drawFrame(QPainter *painter, qreal angle);
void drawPointer(QPainter *painter, qreal angle);
void drawSpeed(QPainter *painter); int speed;
int time_id;
int status; };
#endif // WIDGET_H

widegt.h

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

main.cpp

QT绘制简易表盘的更多相关文章

  1. QT绘制饼图

    QT版本:QT5.6.1 QT绘制饼图,出问题的代码如下 void DrawPieDialog::paintEvent(QPaintEvent *event) { float startAngle=0 ...

  2. Qt 学习之路 2(24):Qt 绘制系统简介

    Qt 学习之路 2(24):Qt 绘制系统简介 豆子 2012年10月30日 Qt 学习之路 2 77条评论 Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于Q ...

  3. Qt项目简易开发原理及常见问题解决

    一.资源下载地址 https://www.aliyundrive.com/s/jBU2wBS8poH 本项目路径:项目->免费->QtDev 注释:为了方便qt全功能开发,QtDev中包含 ...

  4. Qt QBarSeries简易柱状图教程

    博客园最强Qt QBarSeries简易柱状图教程 前情提要 每个人的绘图需求不同,此篇教程也是根据需求来改的.我的需求大概如下所示. 通过信号槽的方式接收signals来刷新柱状图,所以每次触发信号 ...

  5. canvas绘制简易时钟

    时钟绘制的非常简易,但该有的都有了. 效果图如下, <!DOCTYPE html> <html> <head lang="en"> <me ...

  6. Qt绘制异形窗体

    异形窗体即不规则窗体,一般采用png图片,一般绘制异形窗体分两步: 1.设置遮罩区 2.绘制图片   使用png图片的透明部分作为遮罩区,然后绘制图片,这样我们就看到一个只绘制了非透明部分的图形,废话 ...

  7. Qt 学习之路 :Qt 绘制系统简介

    Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类. QPainter用来执行绘制的 ...

  8. qt绘制设备

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.QtGui import  * from Py ...

  9. QT绘制系统简介

    #3个类:QPainter,QPainterDevice 和 QPaintEngine 三个类 #qpainter用于执行绘制操作 #QPainterDevice是一个二维空间抽象,允许qpainte ...

随机推荐

  1. Kernighan《UNIX 传奇:历史与回忆》杂感

    Brian W. Kernighan 是一个伟大的技术作家,我买了他写的几乎所有书.他近些年的书我买的是 Kindle 电子版,不占地方. 以下是我手上保存的纸版书: Kernighan 的书大多与别 ...

  2. Wordpress学习链接整理

    Wordpress学习链接整理 获取和使用 WordPress 中的全局变量 wordpress模板加载顺序汇总 WordPress载入页面时的模板加载机制(图) WordPress 条件判断标签及用 ...

  3. hdu2067 简单dp或者记忆化搜索

    题意: 小兔的棋盘 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  4. 一个DDOS木马后门病毒的分析

    http://blog.csdn.net/qq1084283172/article/details/49305827 一.样本信息 文件名称:803c617e665ff7e0318386e24df63 ...

  5. Python中Numpy模块的使用

    目录 NumPy ndarray对象 Numpy数据类型 Numpy数组属性 NumPy NumPy(Numerical Python) 是 Python 的一个扩展程序库,支持大量的维度数组与矩阵运 ...

  6. CVE-2017-11826:Office Open XML 标签嵌套解析混淆漏洞

    \x01 前言 CVE-2017-11826 据说是 360 在 2017 年 9 月底发现的一个关于 XML 格式解析的一个漏洞,之后微软在 10 月份发布了关于 CVE-2017-11826 的补 ...

  7. 微言Netty:百万并发基石上的epoll之剑

    说道本章标题,相信很多人知道我在暗喻石中剑这个典故,在此典故中,天命注定的亚瑟很容易的就拔出了这把石中剑,但是由于资历不被其他人认可,所以他颇费了一番周折才成为了真正意义上的英格兰全境之王,亚瑟王.说 ...

  8. 提升50%!Presto如何提升Hudi表查询性能?

    分享一篇关于使用Hudi Clustering来优化Presto查询性能的talk talk主要分为如下几个部分 演讲者背景介绍 Apache Hudi介绍 数据湖演进和用例说明 Hudi Clust ...

  9. python模块导入原理

    转自:http://blog.csdn.net/u012422440/article/details/41791433 今日在自学Python,借此机会,正好重新开始写博文,既可以巩固python的知 ...

  10. Django(24)永久重定向和临时重定向

    重定向 重定向分为永久重定向和临时重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面.比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面. ...