先看看效果:
一、思路
该温度计的实现包含两个方面。其一是绘制,其二是动画。
绘制主要由背景、刻度值和中间的柱体三部分组成。
温度计最关键的属性是温度值,所以动画只要关联温度值属性即可。
二、实现关键点
1.首先我们需要一个类继承于QWidget,重写paintEvent事件以便于我们能够进行绘制操作。
2.定义一个温度值属性,并用Q_PROPERTY声明这个属性(动画绑定属性时需要),然后写属性的READ和WRITE对应的函数。
Q_PROPERTY(qreal value READ getValue WRITE setValue) //声明属性 void setValue(qreal value); //设置值 qreal getValue(); //获取值 qreal m_value; //温度值
3.定义一个动画变量,并绑定value属性(属性名与Q_PROPERTY声明的一致)。
m_valueAnimation = new QPropertyAnimation(this,"value",this);
m_valueAnimation->setDuration(1000); //动画时间1秒
m_valueAnimation->setEasingCurve(QEasingCurve::OutCubic); //动画效果
4.绘制
根据大小计算中间柱子的矩形区域m_rect,其他内容的绘制将基于m_rect计算:
void CThermometer::updateRect() { m_rect.setX((this->width() - m_width)/2); m_rect.setY(m_nPadTop); //顶部预留 m_rect.setWidth(m_width); //减去顶部和底部预留以及底部圆形的高度。 m_rect.setHeight(this->height() - m_nPadTop - m_nPadBottom - CIRCLE_RADIUS*m_width); }
接着按顺序绘制:
//中心柱子底色 painter.fillRect(m_rect,QColor(168,200,225)); //圆-放置在m_rect的底部 painter.save(); QRectF tmpRect = QRectF(m_rect.bottomLeft(),QSizeF(m_width,m_width*CIRCLE_RADIUS)); painter.fillRect(tmpRect,QColor(255,0,0)); painter.setPen(Qt::NoPen); painter.setBrush(QColor(255,0,0)); painter.drawEllipse(tmpRect.bottomLeft() + QPointF(tmpRect.width()/2,0),m_width*CIRCLE_RADIUS,m_width*CIRCLE_RADIUS); painter.restore(); //画刻度-放置在m_rect的左右两侧 painter.save(); painter.setPen(m_scaleColor); int nYcount = (m_maxValue - m_minValue)/10 + 1; //分为几个大刻度(预留1个十度上下各0.5个) qreal perHeight = m_rect.height()/nYcount; int nPrecisionCount = 10/(int)m_precision; qreal precisionHeight = perHeight/nPrecisionCount; //最小刻度 QFontMetricsF fMetrics(painter.font()); for(int i = 0; i < nYcount; ++i) { //左侧刻度 QPointF basePoint = m_rect.bottomLeft() + QPointF(0,-perHeight/2) + QPointF(-2,-perHeight*i); painter.drawLine(basePoint,basePoint + QPointF(-8,0)); //左侧大刻度 if(i != nYcount - 1) { for(int j = 1; j < nPrecisionCount; ++j) { painter.drawLine(basePoint + QPointF(0,-precisionHeight*j),basePoint + QPointF(-5,-precisionHeight*j)); //左侧小刻度 } } //刻度值 QString text = QString::number(m_minValue + 10*i); QRectF textRect(basePoint + QPointF(-8,0),QSizeF(fMetrics.width(text),fMetrics.height())); textRect.adjust(-textRect.width() - 5,-textRect.height()/2,-textRect.width() - 5,-textRect.height()/2); painter.drawText(textRect,Qt::AlignCenter,text); //右侧刻度 basePoint = m_rect.bottomRight() + QPointF(0,-perHeight/2) + QPointF(2,-perHeight*i); painter.drawLine(basePoint,basePoint + QPointF(8,0)); if(i != nYcount - 1) { for(int j = 1; j < nPrecisionCount; ++j) { painter.drawLine(basePoint + QPointF(0,-precisionHeight*j),basePoint + QPointF(5,-precisionHeight*j)); //左侧小刻度 } } } painter.restore(); //值-根据m_value和最大最小值计算在m_rect中所占的百分数。 qreal h = (m_value - m_minValue + 5)/(m_maxValue - m_minValue + 10)*m_rect.height(); if(h < 0) h = 0; if(h > m_rect.height()) h = m_rect.height(); painter.fillRect(m_rect.adjusted(0,m_rect.height() - h,0,0),QColor(255,0,0));
发表评论