Qt:绘制仪表盘

本文转载于用户MANY_L的文章Qt总结之八:绘制仪表盘,链接为:https://blog.csdn.net/Aidam_Bo/article/details/85266798

前言

(1)QPainter用来执行具体的绘图相关的操作,用来画点,线,填充,变换,alpha/阿尔法通道(透明度)。Alpha的值越大,就越不透明,范围是0-255,255就是不透明,0就是完全透明;当对应 RGB 颜色时, Alpha 会叠加到颜色上面;只有当 Alpha 通道是255时,才是其真正的颜色。

(2)QPainterDevice是Qpainter用来绘图设备,Qt中有几种绘图的设备,如QWidget,Qpainter,QPaxmip 都是从QPainterDevice继承的。例如QPainter painter(this); 把绘图设备指针传递painter,把当前控件指针初始化。

(3)QPainterEngine类提供了不同类型设备接口,对程序员不透明,由QPainter,QpaintDevive类进行交互 。
一个绘图的操作流程就是:对一个QPainterDevice直接或间接调用Qpainter类。Qpainter类内部调用QpaintEngine进行绘图

(4)QPainterEngine类通常是由QPainterDevice类负责创建和管理。
Qwidget类,最低层的类,接收鼠标,键盘和从其他敞口系统的事件,并且绘制在屏幕上。

(5)QPaintDevice类是所有可以绘制的对象的基类。个绘制设备就是一个可以使用QPainter来绘制的二维空间的抽象。绘画的能力由子类QWidget、QPixmap、QPicture和QPrinter来实现。绘制设备的默认坐标系统的原点在左上角。X向右增加,Y向下增加。单位是一个像素。这里有几种方法在使用绘制工具时来设置用户自定义的坐标系统,

(6)Qt 绘图系统定义了两个绘制时使用的关键属性:画刷和画笔。(1)画刷使用QBrush描述,大多用于填充;(2)画笔使用QPen描述,大多用于绘制轮廓线。

(7)QBrush定义了QPainter的填充模式,具有样式、颜色、渐变以及纹理等属性。画刷的style()定义了填充的样式,使用Qt::BrushStyle枚举,默认值是Qt::NoBrush,也就是不进行任何填充。QPen定义了用于QPainter应该怎样画线或者轮廓线。画笔具有样式、宽度、画刷、笔帽样式和连接样式等属性。画笔的样式style()定义了线的样式。画刷brush()用于填充画笔所绘制的线条。

参考网址:http://blog.csdn.net/zhang_xch/article/details/9051067

1. 绘制

绘图的基本函数

#ifndef SPEED_H
#define SPEED_H
 
#include 
#include "ui_speed.h"
 
class Speed : public QWidget
{
	Q_OBJECT
 
public:
	Speed(QWidget *parent = 0);
	~Speed();
 
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);
 
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:
	Ui::SpeedClass ui;
};
 
#endif // SPEED_H

上面的代码是能够绘画出图片的重要函数-重绘函数。只要出现以下几种情况,系统就会自动调用paintEvent方法。
a)当窗口部件第一次显示时,系统会自动产生一个绘图事件
b)重新调整窗口部件大小
c)当窗口部件被其他部件遮挡,然后又再次显示出来时,就会对隐藏的区域产生一个重绘事件
translate(qreal dx, qreal dy);坐标变换可以看做是painter当前的一个状态,我们可以用save()方法把当前的状态存到一个堆栈里,在用过 之后,再用restore()恢复

注:
坐标系统在绘制的过程中是至关重要的,首先做好坐标变换,把窗体的中心设置成坐标原点,(默认的坐标原点的窗体的左上方(0,0)向右是x->增长,向下是y->增长。)

2. 绘制仪表盘

2.1 绘制表冠

首先就要绘制出两个个圆形,设置圆形的背景色,背景色采用渐变填充的方式,通过两个设置两个圆不同的填充颜色来形成一个色环,形成表冠。函数如下。使用的是线性渐变 QLinearGradient

QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, qreal yFinalStop); 

使用这个类实例化一个对象。对象的四个参数,分别是 两个点的坐标,表示渐变的方向。

setColorAt(qreal pos, const QColor &color); 

pos是一个[0,1]的闭区间的数字。设置渐变坐标所表示的距离。的比例大小,0.2就是长度的1/5

painter->save();
painter->restore();

基本上都是一起出现的,前者是保存当前坐标,然后进行变换操,后者是将以前的坐标系状 态恢复,其实就是一个入栈和出栈的操作。

void Speed::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(-rad ius, -radius, radius << 1, radius << 1); 
painter->setBrush(m_background = Qt::black); 
painter->drawEllipse(-92, -92, 184, 184); 
painter->restore(); 
}

2.2 绘制刻度值

通过一套算法来实现绘制数字刻度

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

2.3 绘制刻度线

rotate(qreal a);//函数实现角度的旋转


 

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

2.4 绘制标题

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

2.5 显示单位与数值

void Speed::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); 
}

2.6 绘制表针,和中心点

void Speed::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);
}

2.7 重绘函数

void Speed ::paintEvent(QPaintEvent *)
{ 
    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);                             /* 画表针 */
 
}

2.8 构造函数的初始化

m_background = Qt::black;
m_foreground = Qt::green;
 
m_startAngle = 60;
m_endAngle = 60;
m_scaleMajor = 10;
m_minValue = 0;
m_maxValue = 100;
m_scaleMajor = 10;//分度
m_scaleMinor = 10;
m_units = "km/h";
m_title = "Speed Meter";
m_precision = 0;
m_value = 0;
 
m_updateTimer = new QTimer(this);
m_updateTimer->setInterval(50);//间隔,微妙微单位,大家可以改一下这个值看看转动速度。
connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(UpdateAngle()));
m_updateTimer->start();//启动定时器
 
setWindowFlags(Qt::FramelessWindowHint);//无窗体
setAttribute(Qt::WA_TranslucentBackground);//背景透明
resize(400, 400);

效果图

表盘中海添加了定时器,来实现动态的效果

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