Переключатель переключения в Qt

Я пытаюсь использовать элемент, который является эквивалентом Android-переключателей в Qt. Я нашел ToggleSwitch в QML, но ничего в реальных С++ Qt libs. Я просто что-то пропустил или мне придется переопределить этот виджет себе?

Ответ 1

Предложение

@piccy - это то, что я сделал для такого тумблера ранее. С несколькими трюками.

Мы должны были эмулировать поведение, подобное переключателям iOS on/off. Это означает, что вам нужно постепенное движение, которое у вас не будет с ползунком с пределом 0-1 без внешних анимаций.

Следовательно, я сделал, чтобы диапазон значений для ползунка был таким же, как максимальная ширина ползунка.

Затем подключите сигнал, выданный слайдером, и проверьте, меньше ли это значение, чем половина максимального значения, и если задано значение ползунка равным 0 else, значение ползунка - макс.

Это даст вам хороший эффект перетаскивания и клип до крайности, когда вы отпустите мышь.

Если вы хотите, чтобы ползунок просто переключался при нажатии на другой стороне без какого-либо перетаскивания, соедините значение измененного значка слайдера и проверьте, чтобы новое значение было ближе к экстремуму, и установите его как значение ползунка, если ползунок не находится в его состояние вниз. Не изменяйте значение ползунка, если слайдер выключен, так как вы можете сломать предыдущее движение перетаскивания.

Ответ 2

Вот пример:

switch.h:

#pragma once
#include <QtWidgets>

class Switch : public QAbstractButton {
    Q_OBJECT
    Q_PROPERTY(int offset READ offset WRITE setOffset)
    Q_PROPERTY(QBrush brush READ brush WRITE setBrush)

public:
    Switch(QWidget* parent = nullptr);
    Switch(const QBrush& brush, QWidget* parent = nullptr);

    QSize sizeHint() const override;

    QBrush brush() const {
        return _brush;
    }
    void setBrush(const QBrush &brsh) {
        _brush = brsh;
    }

    int offset() const {
        return _x;
    }
    void setOffset(int o) {
        _x = o;
        update();
    }

protected:
    void paintEvent(QPaintEvent*) override;
    void mouseReleaseEvent(QMouseEvent*) override;
    void enterEvent(QEvent*) override;

private:
    bool _switch;
    qreal _opacity;
    int _x, _y, _height, _margin;
    QBrush _thumb, _track, _brush;
    QPropertyAnimation *_anim = nullptr;
};

switch.cpp:

Switch::Switch(QWidget *parent) : QAbstractButton(parent),
_height(16),
_opacity(0.000),
_switch(false),
_margin(3),
_thumb("#d5d5d5"),
_anim(new QPropertyAnimation(this, "offset", this))
{
    setOffset(_height / 2);
    _y = _height / 2;
    setBrush(QColor("#009688"));
}

Switch::Switch(const QBrush &brush, QWidget *parent) : QAbstractButton(parent),
_height(16),
_switch(false),
_opacity(0.000),
_margin(3),
_thumb("#d5d5d5"),
_anim(new QPropertyAnimation(this, "offset", this))
{
    setOffset(_height / 2);
    _y = _height / 2;
    setBrush(brush);
}

void Switch::paintEvent(QPaintEvent *e) {
    QPainter p(this);
    p.setPen(Qt::NoPen);
    if (isEnabled()) {
        p.setBrush(_switch ? brush() : Qt::black);
        p.setOpacity(_switch ? 0.5 : 0.38);
        p.setRenderHint(QPainter::Antialiasing, true);
        p.drawRoundedRect(QRect(_margin, _margin, width() - 2 * _margin, height() - 2 * _margin), 8.0, 8.0);
        p.setBrush(_thumb);
        p.setOpacity(1.0);
        p.drawEllipse(QRectF(offset() - (_height / 2), _y - (_height / 2), height(), height()));
    } else {
        p.setBrush(Qt::black);
        p.setOpacity(0.12);
        p.drawRoundedRect(QRect(_margin, _margin, width() - 2 * _margin, height() - 2 * _margin), 8.0, 8.0);
        p.setOpacity(1.0);
        p.setBrush(QColor("#BDBDBD"));
        p.drawEllipse(QRectF(offset() - (_height / 2), _y - (_height / 2), height(), height()));
    }
}

void Switch::mouseReleaseEvent(QMouseEvent *e) {
    if (e->button() & Qt::LeftButton) {
        _switch = _switch ? false : true;
        _thumb = _switch ? _brush : QBrush("#d5d5d5");
        if (_switch) {
            _anim->setStartValue(_height / 2);
            _anim->setEndValue(width() - _height);
            _anim->setDuration(120);
            _anim->start();
        } else {
            _anim->setStartValue(offset());
            _anim->setEndValue(_height / 2);
            _anim->setDuration(120);
            _anim->start();
        }
    }
    QAbstractButton::mouseReleaseEvent(e);
}

void Switch::enterEvent(QEvent *e) {
    setCursor(Qt::PointingHandCursor);
    QAbstractButton::enterEvent(e);
}

QSize Switch::sizeHint() const {
    return QSize(2 * (_height + _margin), _height + 2 * _margin);
}

main.cpp:

#include "switch.h"

    int main(int argc, char *argv[]) {
        QApplication a(argc, argv);
        QWidget *widget = new QWidget;
        widget->setWindowFlags(Qt::FramelessWindowHint);
        QHBoxLayout layout;
        widget->setLayout(&layout);
        Switch *_switch = new Switch;
        Switch *_switch2 = new Switch;
        _switch2->setDisabled(true);
        layout.addWidget(_switch);
        layout.addWidget(_switch2);
        widget->show();
        return a.exec();
    }

введите описание изображения здесь

Ответ 3

Ну, вам придется использовать QCheckBox. Это не Toggle Switch, но он делает то же самое. Если вам действительно нужна визуальная визуализация, вам нужно создать собственный виджет

Ответ 4

Давита права в своем ответе, где это касается флажков. Однако если вы ищете что-то похожее на третий пример (переключатели включения/выключения), вы можете просто использовать для этого два QPushButton и установить они должны быть checkable. Сделайте их autoexclusive одновременно, и вам должно быть хорошо идти.

С небольшим визуальным стилем с помощью таблицы стилей вы сможете приблизиться, если не на месте.

Ответ 5

Вы также можете сделать это с помощью элемента управления QSlider в горизонтальной ориентации, который имеет диапазон от 0 до 1. Вам, вероятно, потребуется установить его максимальную ширину примерно на 50 или около того, чтобы он не растягивался по ширине диалога. Затем вы можете настроить его с помощью таблицы стилей, чтобы улучшить внешний вид, или подклассировать его, и сами потянуть элементы управления. Это может не потребовать слишком много кода, чтобы он выглядел хорошо.

Ответ 6

Также см. QRadioButton и QPushButton с checkable, и некоторые стили или пользовательские чертежи могут быть сделаны как "Переключатели включения/выключения"

Ответ 7

Я знаю, что эта ветка устарела, но я очень сильно боролся с этой конкретной проблемой, несмотря на то, что Viv дал очень хороший совет.

В любом случае, я подумал, что поделюсь решением, которое я придумал здесь, возможно, это поможет кому-то еще на этом пути.

void Switch::on_sldSwitch_actionTriggered(int action) {
    if(action != 7) ui->sldSwitch->setValue((action%2) ? 100 : 0);
}

void Switch::on_sldSwitch_sliderReleased() {
    ui->sldSwitch->setValue((ui->sldSwitch->sliderPosition() >= 50) ? 100 : 0);
}

Небольшое объяснение: actionTriggered будет вызываться каждый раз при нажатии или перемещении слайдера с клавиатуры. Когда он будет перетаскиваться, он выдаст сигнал "7". Чтобы избежать немедленного щелчка, действие 7 блокируется.

При перемещении вправо он выделяет 3 при нажатии и 1 при нажатии "справа" (или "вниз" ) на клавиатуре, поэтому мы стреляем вправо, когда это не четное число.

При перемещении влево он испускает 2 или 4.

sliderReleased() будет вызван, как только вы отпустите кнопку мыши после перетаскивания, однако в этот момент ползунок все еще имеет свое старое значение (которое немного меня подтолкнуло). Итак, чтобы получить правильное положение для привязки к я запросил sliderPosition вместо value и это.

Я надеюсь, что это поможет кому-то.