文章目录
一、实现图片circle显示
大概思路是:
先获得一个周边透明的圆形画布(安卓是画布,这里是painter),然后将要显示的图片画上去,这样获得了圆形的pixmap,将pixmap设置到QLabel上后OK。
void CircleLabel::setCirclePixmap(const QPixmap & circlepixmap)
{
QPixmap pixmap(this->width(),this->height());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QPainterPath path;
path.addEllipse(0, 0, this->width(),this->height());
painter.setClipPath(path);
painter.drawPixmap(0, 0, this->width(),this->height(), circlepixmap);
this->setPixmap(pixmap);
}
二、旋转动画功能
1,一种是通过设置定时器不停地更新
如下代码:
timerRotate_ = new QTimer(this);
connect(timerRotate_, &QTimer::timeout, this, &SelfDialog::slotRotateTimeout);
timerRotate_->start(100);
void SelfDialog::slotRotateTimeout()
{
QMatrix matrix;
matrix.rotate(180 * rotateStep_++);
QPixmap orig = QPixmap(":/img/rotate_pic.png");
QPixmap rotated = orig.transformed(matrix, Qt::SmoothTransformation);
ui->labelRotate->setPixmap(rotated);
rotateStep_ %= 2;
}
这种是在调用QLabel的地方设置一个定时器、一个角度值变量angle。比如定时每隔100ms执行一次,并且通过定时器的信号函数timeout触发的槽函数中执行,变化一次角度值变量angle,并且将angle值设置给QLabel中。
这种方式显然不够好,每个地方都要使用的话,代码冗余、耦合度太高(包括内容耦合、控制耦合等)、没有做到内聚(包括功能内聚、顺序内聚、通信内聚、过程内聚等)(触发条件需要使用定时器,增加了对定时器的控制代码,值需要在定时器中自己修改变化,然后还要单独的将值设置给QLabel)。
但是这里做到了自己控制刷新频率,灵活控制,并且可以通过合理降低频率达到性能的最大化。
2,第二种方法是使用属性动画QPropertyAnimation
在自定义的QLabel中添加如下代码:
Q_PROPERTY(int rotation READ rotation WRITE setRotation)
/**
* @brief setRotation 为了使用属性动画QPropertyAnimation(this, "rotation")
* @param rotation
*/
void setRotation(int rotation);
/**
* @brief rotation 为了使用属性动画QPropertyAnimation(this, "rotation")
* @return
*/
int rotation() const;
使用时直接就是按照普通的属性动画的使用,代码如下:
animation_ = new QPropertyAnimation(ui->labelLoadingIcon, "rotation");
animation_->setDuration(4000);
animation_->setStartValue(0);
animation_->setEndValue(360);
animation_->setLoopCount(-1); //旋转次数
// connect(animation, SIGNAL(finished()), this, SLOT(onAnimation()));
animation_->start(QAbstractAnimation::KeepWhenStopped);
这种方法使用起来要方便很多,代码也已经完全的按照属性动画使用,触发事件、属性值的变化等都已经由属性动画完成,需要做的只是在自定义的QLabel中添加这个属性刷新时的具体行为。
但是这种方法也有一个很大的缺陷,无法控制触发事件执行的频率,如果本身这个属性的刷新执行的操作是很消耗性能的,那么这样就很不划算
3,结合上面两种方法的优缺点,自己总结了第三种方法
这是在第二种方法的基础上优化而来的,解决了刷新频率的不可控问题,合理提高了性能。其实就是在第二种方法的基础上加了一个每隔100ms的刷新过滤,大于100ms执行刷新,小于则不作操作。
代码如下:
void CircleLabel::setRotation(int rotation)
{
this->rotation_ = rotation;
//perfect cpu usage
if(!qTimeFilterRotate_.isValid()){
qTimeFilterRotate_.start();
}
else{
if(qTimeFilterRotate_.elapsed() > 100){
qTimeFilterRotate_.restart();
}
else{
return;
}
}
//can use QMatrix to rotate
// QMatrix matrix;
// matrix.rotate(rotation/180 * 180);
//use painter to rotate
//让图片围绕中心旋转
int imageWidth = pixmapOrigin_.width();
int imageHeight = pixmapOrigin_ .height();
QPixmap temp(pixmapOrigin_.size());
temp.fill(Qt::transparent);
QPainter painter(&temp);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.translate(imageWidth / 2, imageHeight / 2);
painter.rotate(rotation); //顺时针旋转90度
painter.translate(-(imageWidth / 2), -(imageHeight / 2)); //使原点复原
painter.drawPixmap(0, 0, pixmapOrigin_);
painter.end();
this->setPixmap(temp);
}
通过第二、三种方法,测试了最近项目的具体性能参数对比,发现CPU使用率降了一个数量级,当然这个在具体项目具体执行的操作中优化程度各异。