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 -》右键“提升为” -》选择自定义的类-》点击“提升”

 据说有第三种方式,可以用插件,直接添加自定义的类。有兴趣的可以去研究一下。

测试:

 

 

posted @ 2024-10-08 15:55  xcywt  阅读(185)  评论(0编辑  收藏  举报
作者:xcywt
出处:https://www.cnblogs.com/xcywt//
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果文中有什么错误,欢迎指出。以免更多的人被误导。