Qt实现自定义控件-按钮
背景:
想着自己实现一个好看一点的按钮,切换时加一点动画。也算巩固一下Qt的基本知识。
基本环境:
主要用到的类有:
QBrush:画刷,主要是画一些颜色啥的。
QPainter:画笔,可以画形状。比如带弧形的矩形,圆形,写字等。
QPropertyAnimation:动画相关。
关键逻辑:
重载paintEvent:实现渲染逻辑,在这里根据不同的状态画出不同的颜色。
重载mousePressEvent:鼠标点击时切换状态。
将QPropertyAnimation::valueChanged信号函数连接起来,获取动画运行时的值,然后重新绘制圆形。
上代码:
一些逻辑和类的用法见注释。
mybutton.h:
#ifndef MYBUTTON_H #define MYBUTTON_H #include <QWidget> #include <QPropertyAnimation> class MyButton : public QWidget { Q_OBJECT public: explicit MyButton(QWidget *parent = nullptr); bool GetIsOff(){return isoff;}; // 提供一个对外接口 signals: void isClicked(); void notifyStatus(bool bOff); // 发一个带参数的信号 protected: void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *event) override; // 鼠标点击事件 void resizeEvent(QResizeEvent* event) override; // 窗口大小发生改变的事件 private: bool isoff = true; // 根据状态去选择不同的颜色 QBrush offBgBrush = Qt::black; QBrush offRBrush = Qt::red; QBrush onBgBrush = Qt::gray; QBrush onRBrush = Qt::green; QString offText = "OFF"; QString onText = "ON"; QPropertyAnimation *animation; // 动画相关 int currentX = height()/2; // 圆形当前的位置 }; #endif // MYBUTTON_H
mybutton.cpp:
#include "mybutton.h" #include <QMouseEvent> #include <QPainter> MyButton::MyButton(QWidget *parent) : QWidget{parent} { setFixedSize(60,30); animation = new QPropertyAnimation(this); animation->setTargetObject(this); animation->setStartValue(height()/2); animation->setEndValue(width() - height()/2); animation->setEasingCurve(QEasingCurve::InOutCirc); // 设置移动的曲线。比如可以先慢后快。这里是设置回弹效果。 animation->setDuration(500); // 移动的持续时间 // 这里用了一个匿名函数 connect(animation, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value){ currentX = value.toInt(); // 动画产生的时候更新当前位置 update(); }); } void MyButton::paintEvent(QPaintEvent *event) { Q_UNUSED(event); // 不使用event时,为了编译时不加告警,用一个宏控制。 QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); // 为了让圆弧边框光滑 int radius = height()/2; painter.setPen(Qt::NoPen); // 把边框去掉. 好看一点。 // 画矩形,两边是圆弧。 painter.setBrush(isoff ? offBgBrush : onBgBrush); painter.drawRoundedRect(this->rect(), radius, radius); // 画圆 painter.setBrush(isoff ? offRBrush : onRBrush); QPoint center; // 画圆的位置 center.setY(radius); //center.setX(isoff ? radius : width() - radius); // 为on状态时,x设置为矩形的右边。也就是宽度-半径 center.setX(currentX); // 根据动画算出来的坐标 painter.drawEllipse(center, radius - radius/10, radius - radius/10); // 正中间显示字 painter.setPen(Qt::white); painter.setFont(QFont("Arial", radius/2)); painter.drawText(this->rect(), Qt::AlignCenter, isoff ? offText : onText); } // 相应点击事件,进行切换。 void MyButton::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton){ // 根据当前状态,调整动画的方向。 isoff ? animation->setDirection(QAbstractAnimation::Forward) : animation->setDirection(QAbstractAnimation::Backward); animation->start(); isoff = !isoff; emit isClicked(); emit notifyStatus(isoff); update(); // 会触发绘图事件,重新绘图。 } } void MyButton::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); // 不使用event时,为了编译时不加告警,用一个宏控制。 animation->setStartValue(height()/2); animation->setEndValue(width() - height()/2); }
如何使用:
介绍两种使用方法:
代码中添加:
方式二:
界面文件中直接添加,具体如下:
直接拖拽一个Widget -》右键“提升为” -》选择自定义的类-》点击“提升”
据说有第三种方式,可以用插件,直接添加自定义的类。有兴趣的可以去研究一下。
测试: