Qt 重写QRadioButton实现动态radioButton源码分享

Qt 重写QRadioButton实现动态radioButton源码分享

一、源码分享

1、效果展示


2、源码分享

2.1、工程结构

2.2、mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->ui->radioButton_2->setColor("#C7E006","#809104");
    this->ui->radioButton_3->setColor("#FF0CE7","#910483");
    this->ui->radioButton_4->setColor("#0C92FF","#0761AC");
}

MainWindow::~MainWindow()
{
    delete ui;
}

2.3、colorfulRadioButton.h

cpp 复制代码
#ifndef COLORFULRADIOBUTTON_H
#define COLORFULRADIOBUTTON_H

#include <QWidget>
#include <QRadioButton>
#include <QPainter>
#include <QPropertyAnimation>

class ColorfulRadioButton : public QRadioButton
{
    Q_OBJECT

    Q_PROPERTY(int bottomLineWidth READ getBottomLineWidth WRITE setBottomLineWidth NOTIFY bottomLineWidthChanged FINAL)
signals:
    void bottomLineWidthChanged();
public:
    explicit ColorfulRadioButton(QWidget *parent = nullptr);

    int getBottomLineWidth() const
    {
        return bottomLineWidth;
    }

    void setBottomLineWidth(int newBottomLineWidth)
    {
        if (bottomLineWidth == newBottomLineWidth)
            return;
        bottomLineWidth = newBottomLineWidth;
        emit bottomLineWidthChanged();
    }
    void setColor(QColor checked,QColor unchecked)
    {
        this->colorChecked = checked;
        this->colorUnchecked = unchecked;
    }
protected:
    void paintEvent(QPaintEvent *e) override;
private:
    QColor colorChecked = "#0BFFB2";
    QColor colorUnchecked = "#0C976B";

    int leftPadding = 5;
    int textX = 0;
    int bottomLineWidth;

    QPropertyAnimation *animBottomLineWidth = nullptr;
};

#endif // COLORFULRADIOBUTTON_H

2.4、colorfulRadioButton.cpp

cpp 复制代码
#include "colorfulRadioButton.h"

ColorfulRadioButton::ColorfulRadioButton(QWidget *parent)
    : QRadioButton{parent}
{
    connect(this,&QRadioButton::toggled,this,
            [=](bool checked)
            {
                if(checked)
                {
                    this->animBottomLineWidth->setStartValue(textX);
                    this->animBottomLineWidth->setEndValue(this->width() - textX);
                    this->animBottomLineWidth->start();
                }
                else
                {
                    this->animBottomLineWidth->setStartValue(this->width() - textX);
                    this->animBottomLineWidth->setEndValue(textX);
                    this->animBottomLineWidth->start();
                }
            });
    this->animBottomLineWidth = new QPropertyAnimation(this,"bottomLineWidth",this);
    this->animBottomLineWidth->setDuration(300);
    connect(this->animBottomLineWidth,&QPropertyAnimation::valueChanged,this,
            [=](const QVariant &value)
            {
                Q_UNUSED(value);
                this->update();
            });

}

void ColorfulRadioButton::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);

    int width = this->width();
    int height = this->height();

    QColor color = this->isChecked()?this->colorChecked:this->colorUnchecked;

    QRect rectRoundBorder(5,5,height-10,height-10);

    painter.setPen(QPen(color, this->isChecked()?4:2, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
    painter.setBrush(Qt::transparent);
    painter.drawEllipse(rectRoundBorder);


    if(this->isChecked())
    {
        //绘制内圆
        int roundWidth = (float)rectRoundBorder.width()/2.0f;
        QRect rectRound(5+roundWidth/2,0+5 + roundWidth/2,roundWidth,roundWidth);

        rectRound.setX(rectRoundBorder.center().x() - roundWidth/2 +1);
        rectRound.setY(rectRoundBorder.center().y() - roundWidth/2 +1);

        painter.setPen(Qt::NoPen);
        painter.setBrush(color);
        painter.drawEllipse(rectRound);

    }
    painter.setPen(QPen(color, 3, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
    QRect rectText(rectRoundBorder.x() + rectRoundBorder.width()+5,0,this->width(),this->height());
    painter.drawText(rectText, Qt::AlignLeft | Qt::AlignVCenter, this->text());
    textX = rectText.x();

    if(bottomLineWidth == 0)
        bottomLineWidth = textX;
    painter.drawLine(QPoint(rectText.x(), height-2),QPoint(bottomLineWidth, height-2));

}

2.5、使用方法

放置一个QRadioButton,然后右键提升:

2.6、完整工程下载

文章顶部下载。

二、实现原理

通过继承相关控件然后通过paintEvent重绘来实现。这是Qt GUI开发中非常核心的技术,用于创建具有独特外观或行为的控件。


1、Qt 控件重写的基本概念

在Qt中,所有的控件(如 QPushButtonQLineEditQComboBox 等)都是 QWidget 的子类。要自定义一个控件,通常需要继承自该控件类,并重写其特定方法。最常见的方法是重写以下事件或方法:

  1. 事件处理函数

    • mousePressEvent(QMouseEvent *event)
    • keyPressEvent(QKeyEvent *event)
    • paintEvent(QPaintEvent *event)(最核心)
  2. 大小相关方法

    • sizeHint()
    • minimumSizeHint()

2、核心重写方法:paintEvent

paintEvent 是绘制控件外观的核心方法。通过重写此方法,你可以完全自定义控件的外观。以下是一个重写 QPushButton 的简单示例:

cpp 复制代码
#include <QPainter>
#include <QPushButton>

class CustomButton : public QPushButton {
public:
    CustomButton(QWidget *parent = nullptr) : QPushButton(parent) {}

protected:
    void paintEvent(QPaintEvent *event) override {
        // 先调用父类的绘制方法(保留基础样式)
        QPushButton::paintEvent(event);

        // 自定义绘制逻辑
        QPainter painter(this);
        painter.setPen(Qt::red);
        painter.drawEllipse(rect().adjusted(5, 5, -5, -5)); // 在按钮上画一个红色圆圈
    }
};

3、完整重写示例:自定义按钮

下面是一个更完整的自定义按钮示例,支持渐变背景和圆角边框:

cpp 复制代码
class GradientButton : public QPushButton {
public:
    GradientButton(const QString &text, QWidget *parent = nullptr)
        : QPushButton(text, parent) {}

protected:
    void paintEvent(QPaintEvent *event) override {
        Q_UNUSED(event);

        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        // 绘制渐变背景
        QLinearGradient gradient(0, 0, width(), height());
        gradient.setColorAt(0, Qt::blue);
        gradient.setColorAt(1, Qt::cyan);
        painter.setBrush(gradient);

        // 绘制圆角矩形
        painter.drawRoundedRect(rect(), 10, 10);

        // 绘制文字(居中)
        painter.setPen(Qt::white);
        painter.drawText(rect(), Qt::AlignCenter, text());
    }
};

4、如何替换事件行为

如果你想改变控件的事件响应逻辑(如鼠标点击),可以重写对应的事件处理器。例如,实现一个双击按钮:

cpp 复制代码
class DoubleClickButton : public QPushButton {
protected:
    void mouseDoubleClickEvent(QMouseEvent *event) override {
        Q_UNUSED(event);
        qDebug() << "Button double-clicked!";
        // 触发自定义逻辑...
    }
};

5、注意事项

  1. 调用父类方法 :在重写 paintEvent 时,通常先调用父类方法(如 QPushButton::paintEvent(event))以保留基础样式,再添加自定义绘制。

  2. 性能优化 :避免在 paintEvent 中执行耗时操作,否则会导致界面卡顿。

  3. 样式表(QSS)vs 重写

    • 简单样式 :使用样式表(如 .setStyleSheet("background: blue;"))。
    • 复杂逻辑 :必须重写 paintEvent

6、总结

需求场景 推荐方法
修改简单样式(颜色、字体) 使用 QSS(样式表)
完全自定义外观 重写 paintEvent
修改事件行为 重写事件处理器

重写控件是Qt高级UI开发的核心技能,通过合理使用 paintEvent 和事件处理器,你可以实现高度定制化的界面效果。

相关推荐
by__csdn2 小时前
Vue3 setup()函数终极攻略:从入门到精通
开发语言·前端·javascript·vue.js·性能优化·typescript·ecmascript
喵了meme2 小时前
C语言实战5
c语言·开发语言
廋到被风吹走2 小时前
【Java】常用设计模式及应用场景详解
java·开发语言·设计模式
Sammyyyyy2 小时前
DeepSeek v3.2 正式发布,对标 GPT-5
开发语言·人工智能·gpt·算法·servbay
Luna-player3 小时前
在前端中,<a> 标签的 href=“javascript:;“ 这个是什么意思
开发语言·前端·javascript
小草cys3 小时前
项目7-七彩天气app任务7.4.2“关于”弹窗
开发语言·前端·javascript
小鸡吃米…3 小时前
Python PyQt6教程三-菜单与工具栏
开发语言·python
aini_lovee3 小时前
寻找 MAC 协议的 MATLAB 仿真
开发语言·macos·matlab
Jelena157795857924 小时前
Java爬虫淘宝拍立淘item_search_img拍接口示例代码
开发语言·python