Qt custom control (switch button)

Qt custom control (switch button)

    • principle
    • Source code
    • operation result

Children who have been exposed to the IOS system should be familiar with the switch button. They often encounter it in the settings. The sliding effect when switching is quite cool.
Generally speaking, the switch button has two states: on and off.
Next, we use custom controls to implement a switch button.

Principle

Override the mouse press event (mousePressEvent) and release event (mouseReleaseEvent) to switch the switch state.
Override the painting event (paintEvent), used to draw the switch effect.
Use QTimer to refresh regularly to produce animation effects when the switch is switched.
The remaining interfaces are used for expansion and can also be expanded by yourself.

Source code

SwitchControl.h

#ifndef SWITCHCONTROL_H
#define SWITCHCONTROL_H


#include <QObject>
#include <QWidget>
#include <QTimer>


class SwitchControl : public QWidget
{<!-- -->
    Q_OBJECT
public:
    explicit SwitchControl(QWidget *parent = nullptr);


    // Return switch status - open: true, closed: false
    bool isToggled() const;


    //Set switch status
    void setToggle(bool checked);


    //Set background color
    void setBackgroundColor(QColor color);


    //Set selected color
    void setCheckedColor(QColor color);


    //Set unavailable colors
    void setDisbaledColor(QColor color);


protected:
    // draw switch
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;


    //Mouse press event
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;


    // Mouse release event - toggle switch status and emit toggled() signal
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;


    // size change event
    void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;




signals:
    //When the state changes, emit a signal
    void toggled(bool checked);


private slots:
    // Used to produce a sliding effect when switching states
    void onTimeout();


private:
    bool m_bChecked; // Is it selected?
    QColor m_background; // Background color
    QColor m_checkedColor; // selected color
    QColor m_disabledColor; // Disabled color
    QColor m_thumbColor; // Thumb color
    qreal m_radius; // rounded corners
    qreal m_nX; // x point coordinates
    qreal m_nY; // y point coordinates
    qint16 m_nHeight; // height
    qint16 m_nMargin; // Margin
    QTimer m_timer; // timer




};


#endif // SWITCHCONTROL_H

SwitchControl.cpp

#include <QPainter>
#include <QMouseEvent>
#include "switchcontrol.h"


SwitchControl::SwitchControl(QWidget *parent)
    : QWidget(parent),
      m_bChecked(false),
      m_background(Qt::black),
      m_checkedColor(QColor(0, 150, 136)),
      m_disabledColor(QColor(190, 190, 190)),
      m_thumbColor(Qt::white),
      m_radius(32.0),
      m_nHeight(64),
      m_nMargin(0)
{<!-- -->
    // Mouse slides over the cursor shape - hand shape
    setCursor(Qt::PointingHandCursor);
    setFixedSize(m_nHeight*3, m_nHeight);


    // Connect signal slot
    connect( & amp;m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
}


// draw switch
void SwitchControl::paintEvent(QPaintEvent *event)
{<!-- -->
    Q_UNUSED(event);


    QPainter painter(this);
    painter.setPen(Qt::NoPen);
    painter.setRenderHint(QPainter::Antialiasing);


    QPainterPath path;
    QColor background;
    QColor thumbColor;
    qreal dOpacity;
    QString stateStr;
    QRectFrect;
    QPen pen(QBrush(QColor(255, 255, 255)), 1);
    QFont font("黑体", 28, QFont::Normal);


    if (isEnabled()) {<!-- --> // Available status


        if (m_bChecked) {<!-- --> // open state
            background = m_checkedColor;
            thumbColor = m_checkedColor;
            dOpacity = 0.600;
            stateStr = QString("On");
            QFontMetrics fmt(font);
            int textWidth = fmt.horizontalAdvance(stateStr);
            int textHeight = fmt.height();
            rect = QRectF(height()*0.3, height()*0.1, textWidth, textHeight);


        } else {<!-- --> //Close state
            background = m_background;
            thumbColor = m_thumbColor;
            dOpacity = 0.800;
            stateStr = QString("Off");
            QFontMetrics fmt(font);
            int textWidth = fmt.horizontalAdvance(stateStr);
            int textHeight = fmt.height();
            rect = QRectF(height()*1.3, height()*0.1, textWidth, textHeight);


        }
    } else {<!-- --> // Unavailable state
        background = m_background;
        dOpacity = 0.260;
        thumbColor = m_disabledColor;
    }
    //Draw a large ellipse
    painter.setBrush(background);
    painter.setOpacity(dOpacity);
    path.addRoundedRect(QRectF(m_nMargin, m_nMargin, width() - 2 * m_nMargin, height() - 2 * m_nMargin), m_radius, m_radius);
    painter.drawPath(path.simplified());
    qDebug("x:%d, y:%d, w:%d, h:%d\\
", m_nMargin, m_nMargin, width() - 2 * m_nMargin, height() - 2 * m_nMargin);


    //Draw a small ellipse
    painter.setBrush(thumbColor);
    painter.setOpacity(1.0);
    painter.drawEllipse(QRectF(m_nX - (m_nHeight / 2), m_nY - (m_nHeight / 2), height(), height()));


    painter.setPen(pen);
    painter.setFont(font);
    painter.drawText(rect, Qt::AlignCenter, stateStr);
}


//Mouse press event
void SwitchControl::mousePressEvent(QMouseEvent *event)
{<!-- -->
    if (isEnabled()) {<!-- -->
        if (event->buttons() & amp; Qt::LeftButton) {<!-- -->
            event->accept();
        } else {<!-- -->
            event->ignore();
        }
    }
}


// Mouse release event - toggle switch status and emit toggled() signal
void SwitchControl::mouseReleaseEvent(QMouseEvent *event)
{<!-- -->
    if (isEnabled()) {<!-- -->
        if ((event->type() == QMouseEvent::MouseButtonRelease) & amp; & amp; (event->button() == Qt::LeftButton)) {<!-- -->
            event->accept();
            m_bChecked = !m_bChecked;
            emit toggled(m_bChecked);
            m_timer.start(3);
        } else {<!-- -->
            event->ignore();
        }
    }
}


// size change event
void SwitchControl::resizeEvent(QResizeEvent *event)
{<!-- -->
    m_nX = m_nHeight / 2;
    m_nY = m_nHeight / 2;
    QWidget::resizeEvent(event);
}




// Switch state - sliding
void SwitchControl::onTimeout()
{<!-- -->
    if (m_bChecked) {<!-- -->
        m_nX + = 1;
        if (m_nX >= width() - m_nHeight/2)
            m_timer.stop();
    } else {<!-- -->
        m_nX -= 1;
        if (m_nX <= m_nHeight / 2)
            m_timer.stop();
    }
    update();
}


// Return switch status - open: true, closed: false
bool SwitchControl::isToggled() const
{<!-- -->
    return m_bChecked;
}


//Set switch status
void SwitchControl::setToggle(bool checked)
{<!-- -->
    m_bChecked = checked;
    m_timer.start(10);
}


//Set background color
void SwitchControl::setBackgroundColor(QColor color)
{<!-- -->
    m_background = color;
}


//Set selected color
void SwitchControl::setCheckedColor(QColor color)
{<!-- -->
    m_checkedColor = color;
}


//Set unavailable colors
void SwitchControl::setDisbaledColor(QColor color)
{<!-- -->
    m_disabledColor = color;
}

For demonstration, you can set the switch style, status and other effects. Calling code:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{<!-- -->
    ui->setupUi(this);
    SwitchControl *pSwitchControl = new SwitchControl(this);
    SwitchControl *pGreenSwitchControl = new SwitchControl(this);
    SwitchControl *pDisabledSwitchControl = new SwitchControl(this);


    QVBoxLayout* vbox = new QVBoxLayout;
    ui->centralwidget->setLayout(vbox);
    vbox->addWidget(pSwitchControl, 1);
    vbox->addWidget(pGreenSwitchControl);
    vbox->addWidget(pDisabledSwitchControl);
    //Set status and style
    pGreenSwitchControl->setToggle(true);
    pGreenSwitchControl->setCheckedColor(QColor(0, 160, 230));
    pGreenSwitchControl->setBackgroundColor(QColor(255, 99, 71));
    pDisabledSwitchControl->setEnabled(true);
    pDisabledSwitchControl->setToggle(true);
    // Connect signal slot
    connect(pSwitchControl, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));


}

void MainWindow::onToggled(bool bChecked)
{<!-- -->
    qDebug() << "State : " << bChecked;
}

Run results