Qt ToggleButton

实现效果

头文件

#pragma once
#include <QWidget>

class QPropertyAnimation;
class ToggleButtonPrivate;
class ToggleButton : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY toggled)
    Q_PROPERTY(qreal indicatorPos READ indicatorPos WRITE setIndicatorPos)

public:
    explicit ToggleButton(QWidget *parent = nullptr);

    void setOnText(const QString &text);
    void setOffText(const QString &text);

    bool isChecked() const;
    void setChecked(bool checked);

    qreal indicatorPos() const;
    void setIndicatorPos(qreal pos);
    void setIndicatorWidth(int w);
    int indicatorWidth() const;

Q_SIGNALS:
    void toggled(bool checked);

protected:
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    QSize sizeHint() const override;

private:
    ToggleButtonPrivate *d_ptr;
    Q_DECLARE_PRIVATE(ToggleButton);
};

实现代码

#include <QPainter>
#include <QMouseEvent>
#include <QEasingCurve>

#include <QPainter>
#include <QPropertyAnimation>
#include <QMouseEvent>

constexpr int kTextTrackSpacing = 4;

class ToggleButtonPrivate
{
public:
    int indicatorWidth = 48; // 默认滑动轨道宽度
    bool checked = false;
    qreal indicatorPos = 0; // 0=off, 1=on
    QString onText{};
    QString offText{};
    QPropertyAnimation *anim = nullptr;
    void startToggleAnimation(bool checked)
    {
        anim->stop();
        anim->setStartValue(indicatorPos);
        anim->setEndValue(checked ? 1.0 : 0.0);
        anim->start();
    }
};

ToggleButton::ToggleButton(QWidget *parent)
    : QWidget(parent)
    , d_ptr(new ToggleButtonPrivate)
{
    setCursor(Qt::PointingHandCursor);
    setMinimumHeight(32);
    setMinimumWidth(60);

    Q_D(ToggleButton);
    d->anim = new QPropertyAnimation(this, "indicatorPos", this);
    d->anim->setDuration(150);
    d->anim->setEasingCurve(QEasingCurve::InOutCubic);

    setChecked(false);
}

void ToggleButton::setOnText(const QString &text)
{
    Q_D(ToggleButton);
    d->onText = text;
    update();
}
void ToggleButton::setOffText(const QString &text)
{
    Q_D(ToggleButton);
    d->offText = text;
    update();
}
bool ToggleButton::isChecked() const
{
    Q_D(const ToggleButton);
    return d->checked;
}

void ToggleButton::setChecked(bool checked)
{
    Q_D(ToggleButton);
    if (d->checked == checked) {
        return;
    }
    d->checked = checked;
    d->startToggleAnimation(checked);
    emit toggled(checked);
}

qreal ToggleButton::indicatorPos() const
{
    Q_D(const ToggleButton);
    return d->indicatorPos;
}

void ToggleButton::setIndicatorPos(qreal pos)
{
    Q_D(ToggleButton);
    d->indicatorPos = pos;
    update();
}

void ToggleButton::setIndicatorWidth(int w)
{
    Q_D(ToggleButton);
    if (d->indicatorWidth != w) {
        d->indicatorWidth = w;
        update();
    }
}
int ToggleButton::indicatorWidth() const
{
    Q_D(const ToggleButton);
    return d->indicatorWidth;
}

void ToggleButton::paintEvent(QPaintEvent *)
{
    Q_D(ToggleButton);
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing, true);

    QFontMetrics fm(font());
    int offTextWidth = fm.horizontalAdvance(d->offText);
    int onTextWidth = fm.horizontalAdvance(d->onText);

    // [OffText][2px][轨道][2px][OnText]
    int trackW = d->indicatorWidth;
    int trackH = height() * 0.8;
    trackH = qMin(trackH, height() - 4);
    int trackX = offTextWidth + kTextTrackSpacing;
    int trackY = (height() - trackH) / 2;
    QRectF trackRect(trackX, trackY, trackW, trackH);

    // 轨道
    QColor bg = d->checked ? QColor("#4CAF50") : QColor("#BDBDBD");
    p.setPen(Qt::NoPen);
    p.setBrush(bg);
    p.drawRoundedRect(trackRect, trackRect.height() / 2, trackRect.height() / 2);

    // knob
    qreal knobDiameter = trackRect.height() - 4;
    qreal knobY = trackRect.top() + 2;
    qreal left = trackRect.left() + 2;
    qreal right = trackRect.right() - knobDiameter - 2;
    qreal knobX = left + (right - left) * d->indicatorPos;
    p.setBrush(Qt::white);
    p.drawEllipse(QRectF(knobX, knobY, knobDiameter, knobDiameter));

    // OffText
    p.setPen(palette().color(QPalette::WindowText));
    p.drawText(QRectF(0, 0, offTextWidth, height()), Qt::AlignVCenter | Qt::AlignLeft, d->offText);

    // OnText
    p.drawText(QRectF(trackX + trackW + kTextTrackSpacing, 0, onTextWidth, height()),
               Qt::AlignVCenter | Qt::AlignLeft,
               d->onText);
}

void ToggleButton::mousePressEvent(QMouseEvent *event)
{
    Q_D(ToggleButton);
    if (event->button() == Qt::LeftButton) {
        setChecked(!d->checked);
    }
    QWidget::mousePressEvent(event);
}

QSize ToggleButton::sizeHint() const
{
    Q_D(const ToggleButton);
    QFontMetrics fm(font());
    int h = qMax((int) (fm.height() * 1.3), d->indicatorWidth / 2 + 4);
    int w = fm.horizontalAdvance(d->offText) + kTextTrackSpacing + d->indicatorWidth
            + kTextTrackSpacing + fm.horizontalAdvance(d->onText);
    return QSize(w, h);
}

使用方式

toggleBtn = new ToggleButton();
toggleBtn->setOnText("On");
toggleBtn->setOffText("Off");
connect(toggleBtn, &ToggleButton::toggled, [=](bool checked) {
    // ...
});
toggleBtn->setChecked(true);

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇