J'essaie d'utiliser un élément qui est l'équivalent de Android Switches in Qt. J'ai trouvé un ToggleSwitch dans QML, mais rien dans les bibliothèques Qt C++ actuelles. Est-ce que je manque juste quelque chose ou devrai-je réimplémenter ce widget moi-même?
La suggestion de @ piccy est ce que j'ai déjà fait pour un tel interrupteur à bascule. Avec quelques ajustements Tho.
Nous avons dû émuler des comportements similaires aux commutateurs d'activation/désactivation iOS. Ce qui signifie que vous aviez besoin d'un mouvement progressif que vous n'aurez pas avec le curseur avec une limite de 0-1 sans animations externes.
Par conséquent, ce que j'ai fait a été de définir la plage de valeurs du curseur sur la même largeur que la largeur maximale du curseur.
Connectez ensuite le signal relâché du curseur et vérifiez si la valeur est inférieure à la moitié du maximum et, le cas échéant, définissez la valeur du curseur sur 0, sinon la valeur du curseur sur max.
Cela vous donnera un bon effet de glissement et réduira les extrêmes lorsque vous relâchez la souris.
Si vous souhaitez que le curseur bascule lorsque vous cliquez dessus de l'autre côté sans glisser, connectez le signal modifié de la valeur du curseur et vérifiez que la nouvelle valeur est plus proche de l'une ou l'autre extrémité et définissez-la comme valeur du curseur si le curseur ne se trouve pas dans son état de panne . Ne changez pas la valeur du curseur si le curseur est abaissé, car vous pourriez alors interrompre le mouvement de déplacement précédent.
Voici un exemple:
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();
}
Nouveau widget de changement de matériau!
style.h
/*
* This is nearly complete Material design Switch widget implementation in qtwidgets module.
* More info: https://material.io/design/components/selection-controls.html#switches
* Copyright (C) 2018 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef STYLE_H
#define STYLE_H
#include <QtCore/qeasingcurve.h>
#define cyan500 QColor("#00bcd4")
#define gray50 QColor("#fafafa")
#define black QColor("#000000")
#define gray400 QColor("#bdbdbd")
Q_DECL_IMPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); // src/widgets/effects/qpixmapfilter.cpp
namespace Style {
using Type = QEasingCurve::Type;
struct Animation {
Animation() = default;
Animation(Type _easing, int _duration) :easing{ _easing }, duration{ _duration } {
}
Type easing;
int duration;
};
struct Switch {
Switch() :
height{ 36 },
font{ QFont("Roboto medium", 13) },
indicatorMargin{ QMargins(8, 8, 8, 8) },
thumbOnBrush{ cyan500 },
thumbOnOpacity{ 1 },
trackOnBrush{ cyan500 },
trackOnOpacity{ 0.5 },
thumbOffBrush{ gray50 },
thumbOffOpacity{ 1 },
trackOffBrush{ black },
trackOffOpacity{ 0.38 },
thumbDisabled{ gray400 },
thumbDisabledOpacity{ 1 },
trackDisabled{ black },
trackDisabledOpacity{ 0.12 },
textColor{ black },
disabledTextOpacity{ 0.26 },
thumbBrushAnimation{ Animation(Type::Linear, 150) },
trackBrushAnimation{ Animation(Type::Linear, 150) },
thumbPosAniamtion{ Animation(Type::InOutQuad, 150) } {
}
int height;
QFont font;
QMargins indicatorMargin;
QColor thumbOnBrush;
double thumbOnOpacity;
QColor trackOnBrush;
double trackOnOpacity;
QColor thumbOffBrush;
double thumbOffOpacity;
QColor trackOffBrush;
double trackOffOpacity;
QColor thumbDisabled;
double thumbDisabledOpacity;
QColor trackDisabled;
double trackDisabledOpacity;
QColor textColor;
double disabledTextOpacity;
Animation thumbBrushAnimation;
Animation trackBrushAnimation;
Animation thumbPosAniamtion;
};
inline QPixmap drawShadowEllipse(qreal radius, qreal elevation, const QColor& color) {
auto px = QPixmap(radius * 2, radius * 2);
px.fill(Qt::transparent);
{ // draw ellipes
QPainter p(&px);
p.setBrush(color);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawEllipse(QRectF(0, 0, px.size().width(), px.size().height()).center(), radius - elevation, radius - elevation);
}
QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
tmp.setDevicePixelRatio(px.devicePixelRatioF());
tmp.fill(0);
QPainter tmpPainter(&tmp);
tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
tmpPainter.drawPixmap(QPointF(), px);
tmpPainter.end();
// blur the alpha channel
QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
blurred.setDevicePixelRatio(px.devicePixelRatioF());
blurred.fill(0);
{
QPainter blurPainter(&blurred);
qt_blurImage(&blurPainter, tmp, elevation * 4., true, false);
}
tmp = blurred;
return QPixmap::fromImage(tmp);
}
} // namespace Style
#endif // STYLE_H
switch.h
/*
* This is nearly complete Material design Switch widget implementation in qtwidgets module.
* More info: https://material.io/design/components/selection-controls.html#switches
* Copyright (C) 2018 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SWITCH_H
#define SWITCH_H
#include <QtWidgets>
#include "style.h"
class Animator : public QVariantAnimation {
Q_OBJECT
Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject)
public:
explicit Animator(QObject* target, QObject* parent = nullptr);
~Animator();
QObject* targetObject() const;
void setTargetObject(QObject* target);
bool isRunning() const {
return state() == Running;
}
void setup(int duration, QEasingCurve easing = QEasingCurve::Linear);
void interpolate(const QVariant& start, const QVariant& end);
protected:
void updateCurrentValue(const QVariant& value) override;
void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override;
private:
QPointer<QObject> target;
};
class SelectionControl :public QAbstractButton {
Q_OBJECT
public:
explicit SelectionControl(QWidget* parent = nullptr);
~SelectionControl();
Qt::CheckState checkState() const;
Q_SIGNALS:
void stateChanged(int);
protected:
void enterEvent(QEvent*) override;
void checkStateSet() override;
void nextCheckState() override;
virtual void toggle(Qt::CheckState state) = 0;
};
class Switch :public SelectionControl {
Q_OBJECT
public:
explicit Switch(QWidget* parent = nullptr);
explicit Switch(const QString& text, QWidget* parent = nullptr);
Switch(const QString& text, const QBrush&, QWidget* parent = nullptr);
~Switch();
QSize sizeHint() const override;
protected:
void paintEvent(QPaintEvent *) override;
void resizeEvent(QResizeEvent*) override;
void toggle(Qt::CheckState) override;
void init();
QRect indicatorRect();
QRect textRect();
static inline QColor colorFromOpacity(const QColor& c, qreal opacity) {
return QColor(c.red(), c.green(), c.blue(), opacity * 255.0);
}
static inline bool ltr(QWidget* w) {
if (w)
return w->layoutDirection() == Qt::LeftToRight;
return false;
}
private:
Style::Switch style;
QPixmap shadowPixmap;
QPointer<Animator> thumbBrushAnimation;
QPointer<Animator> trackBrushAnimation;
QPointer<Animator> thumbPosAniamtion;
};
#endif // SWITCH_H
switch.cpp
/*
* This is nearly complete Material design Switch widget implementation in qtwidgets module.
* More info: https://material.io/design/components/selection-controls.html#switches
* Copyright (C) 2018 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "switch.h"
#define CORNER_RADIUS 8.0
#define THUMB_RADIUS 14.5
#define SHADOW_ELEVATION 2.0
Animator::Animator(QObject* target, QObject* parent) : QVariantAnimation(parent) {
setTargetObject(target);
}
Animator::~Animator() {
stop();
}
QObject* Animator::targetObject() const {
return target.data();
}
void Animator::setTargetObject(QObject *_target) {
if (target.data() == _target)
return;
if (isRunning()) {
qWarning("Animation::setTargetObject: you can't change the target of a running animation");
return;
}
target = _target;
}
void Animator::updateCurrentValue(const QVariant& value) {
Q_UNUSED(value);
if (!target.isNull()) {
auto update = QEvent(QEvent::StyleAnimationUpdate);
update.setAccepted(false);
QCoreApplication::sendEvent(target.data(), &update);
if (!update.isAccepted())
stop();
}
}
void Animator::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) {
if (target.isNull() && oldState == Stopped) {
qWarning("Animation::updateState: Changing state of an animation without target");
return;
}
QVariantAnimation::updateState(newState, oldState);
if (!endValue().isValid() && direction() == Forward) {
qWarning("Animation::updateState (%s): starting an animation without end value", targetObject()->metaObject()->className());
}
}
void Animator::setup(int duration, QEasingCurve easing) {
setDuration(duration);
setEasingCurve(easing);
}
void Animator::interpolate(const QVariant& _start, const QVariant& end) {
setStartValue(_start);
setEndValue(end);
start();
}
SelectionControl::SelectionControl(QWidget * parent) :QAbstractButton(parent) {
setObjectName("SelectionControl");
setCheckable(true);
}
SelectionControl::~SelectionControl() {
}
void SelectionControl::enterEvent(QEvent* e) {
setCursor(Qt::PointingHandCursor);
QAbstractButton::enterEvent(e);
}
Qt::CheckState SelectionControl::checkState() const {
return isChecked() ? Qt::Checked : Qt::Unchecked;
}
void SelectionControl::checkStateSet() {
const auto state = checkState();
emit stateChanged(state);
toggle(state);
}
void SelectionControl::nextCheckState() {
QAbstractButton::nextCheckState();
SelectionControl::checkStateSet();
}
void Switch::init() {
setFont(style.font);
setObjectName("Switch");
/* setup animations */
thumbBrushAnimation = new Animator{ this, this };
trackBrushAnimation = new Animator{ this, this };
thumbPosAniamtion = new Animator{ this, this };
thumbPosAniamtion->setup(style.thumbPosAniamtion.duration, style.thumbPosAniamtion.easing);
trackBrushAnimation->setup(style.trackBrushAnimation.duration, style.trackBrushAnimation.easing);
thumbBrushAnimation->setup(style.thumbBrushAnimation.duration, style.thumbBrushAnimation.easing);
/* set init values */
trackBrushAnimation->setStartValue(colorFromOpacity(style.trackOffBrush, style.trackOffOpacity));
trackBrushAnimation->setEndValue(colorFromOpacity(style.trackOffBrush, style.trackOffOpacity));
thumbBrushAnimation->setStartValue(colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity));
thumbBrushAnimation->setEndValue(colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity));
/* set standard palettes */
auto p = palette();
p.setColor(QPalette::Active, QPalette::ButtonText, style.textColor);
p.setColor(QPalette::Disabled, QPalette::ButtonText, style.textColor);
setPalette(p);
setSizePolicy(QSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Fixed));
}
QRect Switch::indicatorRect() {
const auto w = style.indicatorMargin.left() + style.height + style.indicatorMargin.right();
return ltr(this) ? QRect(0, 0, w, style.height) : QRect(width() - w, 0, w, style.height);
}
QRect Switch::textRect() {
const auto w = style.indicatorMargin.left() + style.height + style.indicatorMargin.right();
return ltr(this) ? rect().marginsRemoved(QMargins(w, 0, 0, 0)) : rect().marginsRemoved(QMargins(0, 0, w, 0));
}
Switch::Switch(QWidget* parent) : SelectionControl(parent) {
init();
}
Switch::Switch(const QString& text, QWidget* parent) : Switch(parent) {
setText(text);
}
Switch::Switch(const QString& text, const QBrush& brush, QWidget* parent) : Switch(text, parent) {
style.thumbOnBrush = brush.color();
style.trackOnBrush = brush.color();
}
Switch::~Switch() {
}
QSize Switch::sizeHint() const {
auto h = style.height;
auto w = style.indicatorMargin.left() + style.height + style.indicatorMargin.right() + fontMetrics().width(text());
return QSize(w, h);
}
void Switch::paintEvent(QPaintEvent *) {
/* for desktop usage we do not need Radial reaction */
QPainter p(this);
const auto _indicatorRect = indicatorRect();
const auto _textRect = textRect();
auto trackMargin = style.indicatorMargin;
trackMargin.setTop(trackMargin.top() + 2);
trackMargin.setBottom(trackMargin.bottom() + 2);
QRectF trackRect = _indicatorRect.marginsRemoved(trackMargin);
if (isEnabled()) {
p.setOpacity(1.0);
p.setPen(Qt::NoPen);
/* draw track */
p.setBrush(trackBrushAnimation->currentValue().value<QColor>());
p.setRenderHint(QPainter::Antialiasing, true);
p.drawRoundedRect(trackRect, CORNER_RADIUS, CORNER_RADIUS);
p.setRenderHint(QPainter::Antialiasing, false);
/* draw thumb */
trackRect.setX(trackRect.x() - trackMargin.left() - trackMargin.right() - 2 + thumbPosAniamtion->currentValue().toInt());
auto thumbRect = trackRect;
if (!shadowPixmap.isNull())
p.drawPixmap(thumbRect.center() - QPointF(THUMB_RADIUS, THUMB_RADIUS - 1.0), shadowPixmap);
p.setBrush(thumbBrushAnimation->currentValue().value<QColor>());
p.setRenderHint(QPainter::Antialiasing, true);
p.drawEllipse(thumbRect.center(), THUMB_RADIUS - SHADOW_ELEVATION - 1.0, THUMB_RADIUS - SHADOW_ELEVATION - 1.0);
p.setRenderHint(QPainter::Antialiasing, false);
/* draw text */
if (text().isEmpty())
return;
p.setOpacity(1.0);
p.setPen(palette().color(QPalette::Active, QPalette::ButtonText));
p.setFont(font());
p.drawText(_textRect, Qt::AlignLeft | Qt::AlignVCenter, text());
} else {
p.setOpacity(style.trackDisabledOpacity);
p.setPen(Qt::NoPen);
// draw track
p.setBrush(style.trackDisabled);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawRoundedRect(trackRect, CORNER_RADIUS, CORNER_RADIUS);
p.setRenderHint(QPainter::Antialiasing, false);
// draw thumb
p.setOpacity(1.0);
if (!isChecked())
trackRect.setX(trackRect.x() - trackMargin.left() - trackMargin.right() - 2);
else
trackRect.setX(trackRect.x() + trackMargin.left() + trackMargin.right() + 2);
auto thumbRect = trackRect;
if (!shadowPixmap.isNull())
p.drawPixmap(thumbRect.center() - QPointF(THUMB_RADIUS, THUMB_RADIUS - 1.0), shadowPixmap);
p.setOpacity(1.0);
p.setBrush(style.thumbDisabled);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawEllipse(thumbRect.center(), THUMB_RADIUS - SHADOW_ELEVATION - 1.0, THUMB_RADIUS - SHADOW_ELEVATION - 1.0);
if (text().isEmpty())
return;
p.setOpacity(style.disabledTextOpacity);
p.setPen(palette().color(QPalette::Disabled, QPalette::ButtonText));
p.setFont(font());
p.drawText(_textRect, Qt::AlignLeft | Qt::AlignVCenter, text());
}
}
void Switch::resizeEvent(QResizeEvent* e) {
shadowPixmap = Style::drawShadowEllipse(THUMB_RADIUS, SHADOW_ELEVATION, QColor(0, 0, 0, 70));
SelectionControl::resizeEvent(e);
}
void Switch::toggle(Qt::CheckState state) {
if (state == Qt::Checked) {
thumbPosAniamtion->interpolate(0, (style.indicatorMargin.left() + style.indicatorMargin.right() + 2) * 2);
thumbBrushAnimation->interpolate(colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity), colorFromOpacity(style.thumbOnBrush, style.thumbOnOpacity));
trackBrushAnimation->interpolate(colorFromOpacity(style.trackOffBrush, style.trackOffOpacity), colorFromOpacity(style.trackOnBrush, style.trackOnOpacity));
} else { // Qt::Unchecked
thumbPosAniamtion->interpolate(thumbPosAniamtion->currentValue().toInt(), 0);
thumbBrushAnimation->interpolate(colorFromOpacity(style.thumbOnBrush, style.thumbOnOpacity), colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity));
trackBrushAnimation->interpolate(colorFromOpacity(style.trackOnBrush, style.trackOnOpacity), colorFromOpacity(style.trackOffBrush, style.trackOffOpacity));
}
}
main.cpp
#include "switch.h"
int main(int argc, char *argv[]) {
QApplication application(argc, argv);
QWidget container;
QVBoxLayout mainLayout;
container.setLayout(&mainLayout);
Switch* switch1 = new Switch("SWITCH");
mainLayout.addWidget(switch1);
Switch* switch2 = new Switch("SWITCH");
mainLayout.addWidget(switch2);
switch2->setDisabled(true);
Switch* switch3 = new Switch("SWITCH");
mainLayout.addWidget(switch3);
switch3->setLayoutDirection(Qt::RightToLeft);
Switch* switch4 = new Switch("SWITCH");
mainLayout.addWidget(switch4);
switch4->setLayoutDirection(Qt::RightToLeft);
switch4->setChecked(true);
switch4->setDisabled(true);
QButtonGroup bg;
Switch* item1 = new Switch("ITEM1");
Switch* item2 = new Switch("ITEM2");
bg.addButton(item1);
bg.addButton(item2);
mainLayout.addWidget(item1);
mainLayout.addWidget(item2);
mainLayout.setMargin(100);
container.show();
return application.exec();
}
Résultat:
Il ya quelques mois, j’ai mis au point une implémentation dont les visuels devaient être plus cohérents avec les styles de bureau courants (versions C++ et Python disponibles; la version Python était le prototype, c’est-à-dire qu’elles pourraient fonctionner différemment). Notez que l'esthétique est entièrement personnalisée à l'aide de paintEvent
. Ne vous attendez pas à des visuels différents selon le système.
Implémentation C++
NOTE: n'oubliez pas les includes (qui ne sont pas dans mon exemple).
_ {Usage:
SwitchButton* sbtn = new SwitchButton(this); // Default style is Style::ONOFF
bool current = sbtn->value();
sbtn->setValue(!current);
(...). hpp
class SwitchButton : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(SwitchButton)
public:
enum Style
{
YESNO,
ONOFF,
BOOL,
EMPTY
};
public:
explicit SwitchButton(QWidget* parent = nullptr, Style style = Style::ONOFF);
~SwitchButton() override;
//-- QWidget methods
void mousePressEvent(QMouseEvent *) override;
void paintEvent(QPaintEvent* event) override;
void setEnabled(bool);
//-- Setters
void setDuration(int);
void setValue(bool);
//-- Getters
bool value() const;
signals:
void valueChanged(bool newvalue);
private:
class SwitchCircle;
class SwitchBackground;
void _update();
private:
bool _value;
int _duration;
QLinearGradient _lg;
QLinearGradient _lg2;
QLinearGradient _lg_disabled;
QColor _pencolor;
QColor _offcolor;
QColor _oncolor;
int _tol;
int _borderradius;
// This order for definition is important (these widgets overlap)
QLabel* _labeloff;
SwitchBackground* _background;
QLabel* _labelon;
SwitchCircle* _circle;
bool _enabled;
QPropertyAnimation* __btn_move;
QPropertyAnimation* __back_move;
};
class SwitchButton::SwitchBackground : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(SwitchBackground)
public:
explicit SwitchBackground(QWidget* parent = nullptr, QColor color = QColor(154, 205, 50), bool rect = false);
~SwitchBackground() override;
//-- QWidget methods
void paintEvent(QPaintEvent* event) override;
void setEnabled(bool);
private:
bool _rect;
int _borderradius;
QColor _color;
QColor _pencolor;
QLinearGradient _lg;
QLinearGradient _lg_disabled;
bool _enabled;
};
class SwitchButton::SwitchCircle : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(SwitchCircle)
public:
explicit SwitchCircle(QWidget* parent = nullptr, QColor color = QColor(255, 255, 255), bool rect = false);
~SwitchCircle() override;
//-- QWidget methods
void paintEvent(QPaintEvent* event) override;
void setEnabled(bool);
private:
bool _rect;
int _borderradius;
QColor _color;
QColor _pencolor;
QRadialGradient _rg;
QLinearGradient _lg;
QLinearGradient _lg_disabled;
bool _enabled;
};
(...). cpp
SwitchButton::SwitchButton(QWidget* parent, Style style)
: QWidget(parent)
, _value(false)
, _duration(100)
, _enabled(true)
{
_pencolor = QColor(120, 120, 120);
_lg = QLinearGradient(35, 30, 35, 0);
_lg.setColorAt(0, QColor(210, 210, 210));
_lg.setColorAt(0.25, QColor(255, 255, 255));
_lg.setColorAt(0.82, QColor(255, 255, 255));
_lg.setColorAt(1, QColor(210, 210, 210));
_lg2 = QLinearGradient(50, 30, 35, 0);
_lg2.setColorAt(0, QColor(230, 230, 230));
_lg2.setColorAt(0.25, QColor(255, 255, 255));
_lg2.setColorAt(0.82, QColor(255, 255, 255));
_lg2.setColorAt(1, QColor(230, 230, 230));
_lg_disabled = QLinearGradient(50, 30, 35, 0);
_lg_disabled.setColorAt(0, QColor(200, 200, 200));
_lg_disabled.setColorAt(0.25, QColor(230, 230, 230));
_lg_disabled.setColorAt(0.82, QColor(230, 230, 230));
_lg_disabled.setColorAt(1, QColor(200, 200, 200));
_offcolor = QColor(255, 255, 255);
_oncolor = QColor(154, 205, 50);
_tol = 0;
_borderradius = 12;
_labeloff = NEW QLabel(this);
_background = NEW SwitchBackground(this, _oncolor);
_labelon = NEW QLabel(this);
_circle = NEW SwitchCircle(this, _offcolor);
__btn_move = NEW QPropertyAnimation(this);
__back_move = NEW QPropertyAnimation(this);
__btn_move->setTargetObject(_circle);
__btn_move->setPropertyName("pos");
__back_move->setTargetObject(_background);
__back_move->setPropertyName("size");
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
_labeloff->setText("Off");
_labelon->setText("On");
_labeloff->move(31, 5);
_labelon->move(15, 5);
setFixedSize(QSize(60, 24));
if (style == Style::YESNO)
{
_labeloff->setText("No");
_labelon->setText("Yes");
_labeloff->move(33, 5);
_labelon->move(12, 5);
setFixedSize(QSize(60, 24));
}
else if (style == Style::BOOL)
{
_labeloff->setText("False");
_labelon->setText("True");
_labeloff->move(37, 5);
_labelon->move(12, 5);
setFixedSize(QSize(75, 24));
}
if (style == Style::EMPTY)
{
_labeloff->setText("");
_labelon->setText("");
_labeloff->move(31, 5);
_labelon->move(12, 5);
setFixedSize(QSize(45, 24));
}
_labeloff->setStyleSheet("color: rgb(120, 120, 120); font-weight: bold;");
_labelon->setStyleSheet("color: rgb(255, 255, 255); font-weight: bold;");
_background->resize(20, 20);
_background->move(2, 2);
_circle->move(2, 2);
}
SwitchButton::~SwitchButton()
{
delete _circle;
delete _background;
delete _labeloff;
delete _labelon;
delete __btn_move;
delete __back_move;
}
void SwitchButton::paintEvent(QPaintEvent*)
{
QPainter* Painter = new QPainter;
Painter->begin(this);
Painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::NoPen);
Painter->setPen(pen);
Painter->setBrush(_pencolor);
Painter->drawRoundedRect(0, 0
, width(), height()
, 12, 12);
Painter->setBrush(_lg);
Painter->drawRoundedRect(1, 1
, width() - 2, height() - 2
, 10, 10);
Painter->setBrush(QColor(210, 210, 210));
Painter->drawRoundedRect(2, 2
, width() - 4, height() - 4
, 10, 10);
if (_enabled)
{
Painter->setBrush(_lg2);
Painter->drawRoundedRect(3, 3
, width() - 6, height() - 6
, 7, 7);
}
else
{
Painter->setBrush(_lg_disabled);
Painter->drawRoundedRect(3, 3
, width() - 6, height() - 6
, 7, 7);
}
Painter->end();
}
void SwitchButton::mousePressEvent(QMouseEvent*)
{
if (!_enabled)
return;
__btn_move->stop();
__back_move->stop();
__btn_move->setDuration(_duration);
__back_move->setDuration(_duration);
int hback = 20;
QSize initial_size(hback, hback);
QSize final_size(width() - 4, hback);
int xi = 2;
int y = 2;
int xf = width() - 22;
if (_value)
{
final_size = QSize(hback, hback);
initial_size = QSize(width() - 4, hback);
xi = xf;
xf = 2;
}
__btn_move->setStartValue(QPoint(xi, y));
__btn_move->setEndValue(QPoint(xf, y));
__back_move->setStartValue(initial_size);
__back_move->setEndValue(final_size);
__btn_move->start();
__back_move->start();
// Assigning new current value
_value = !_value;
emit valueChanged(_value);
}
void SwitchButton::setEnabled(bool flag)
{
_enabled = flag;
_circle->setEnabled(flag);
_background->setEnabled(flag);
if (flag)
_labelon->show();
else
{
if (value())
_labelon->show();
else
_labelon->hide();
}
QWidget::setEnabled(flag);
}
void SwitchButton::setDuration(int time)
{
_duration = time;
}
void SwitchButton::setValue(bool flag)
{
if (flag == value())
return;
else
{
_value = flag;
_update();
setEnabled(_enabled);
}
}
bool SwitchButton::value() const
{
return _value;
}
void SwitchButton::_update()
{
int hback = 20;
QSize final_size(width() - 4, hback);
int y = 2;
int xf = width() - 22;
if (_value)
{
final_size = QSize(hback, hback);
xf = 2;
}
_circle->move(QPoint(xf, y));
_background->resize(final_size);
}
SwitchButton::SwitchBackground::SwitchBackground(QWidget* parent, QColor color, bool rect)
: QWidget(parent)
, _rect(rect)
, _borderradius(12)
, _color(color)
, _pencolor(QColor(170, 170, 170))
{
setFixedHeight(20);
_lg = QLinearGradient(0, 25, 70, 0);
_lg.setColorAt(0, QColor(154, 194, 50));
_lg.setColorAt(0.25, QColor(154, 210, 50));
_lg.setColorAt(0.95, QColor(154, 194, 50));
_lg_disabled = QLinearGradient(0, 25, 70, 0);
_lg_disabled.setColorAt(0, QColor(190, 190, 190));
_lg_disabled.setColorAt(0.25, QColor(230, 230, 230));
_lg_disabled.setColorAt(0.95, QColor(190, 190, 190));
if (_rect)
_borderradius = 0;
_enabled = true;
}
SwitchButton::SwitchBackground::~SwitchBackground()
{
}
void SwitchButton::SwitchBackground::paintEvent(QPaintEvent*)
{
QPainter* Painter = new QPainter;
Painter->begin(this);
Painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::NoPen);
Painter->setPen(pen);
if (_enabled)
{
Painter->setBrush(QColor(154, 190, 50));
Painter->drawRoundedRect(0, 0
, width(), height()
, 10, 10);
Painter->setBrush(_lg);
Painter->drawRoundedRect(1, 1, width()-2, height()-2, 8, 8);
}
else
{
Painter->setBrush(QColor(150, 150, 150));
Painter->drawRoundedRect(0, 0
, width(), height()
, 10, 10);
Painter->setBrush(_lg_disabled);
Painter->drawRoundedRect(1, 1, width() - 2, height() - 2, 8, 8);
}
Painter->end();
}
void SwitchButton::SwitchBackground::setEnabled(bool flag)
{
_enabled = flag;
}
SwitchButton::SwitchCircle::SwitchCircle(QWidget* parent, QColor color, bool rect)
: QWidget(parent)
, _rect(rect)
, _borderradius(12)
, _color(color)
, _pencolor(QColor(120, 120, 120))
{
setFixedSize(20, 20);
_rg = QRadialGradient(static_cast<int>(width() / 2), static_cast<int>(height() / 2), 12);
_rg.setColorAt(0, QColor(255, 255, 255));
_rg.setColorAt(0.6, QColor(255, 255, 255));
_rg.setColorAt(1, QColor(205, 205, 205));
_lg = QLinearGradient(3, 18, 20, 4);
_lg.setColorAt(0, QColor(255, 255, 255));
_lg.setColorAt(0.55, QColor(230, 230, 230));
_lg.setColorAt(0.72, QColor(255, 255, 255));
_lg.setColorAt(1, QColor(255, 255, 255));
_lg_disabled = QLinearGradient(3, 18, 20, 4);
_lg_disabled.setColorAt(0, QColor(230, 230, 230));
_lg_disabled.setColorAt(0.55, QColor(210, 210, 210));
_lg_disabled.setColorAt(0.72, QColor(230, 230, 230));
_lg_disabled.setColorAt(1, QColor(230, 230, 230));
_enabled = true;
}
SwitchButton::SwitchCircle::~SwitchCircle()
{
}
void SwitchButton::SwitchCircle::paintEvent(QPaintEvent*)
{
QPainter* Painter = new QPainter;
Painter->begin(this);
Painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::NoPen);
Painter->setPen(pen);
Painter->setBrush(_pencolor);
Painter->drawEllipse(0, 0, 20, 20);
Painter->setBrush(_rg);
Painter->drawEllipse(1, 1, 18, 18);
Painter->setBrush(QColor(210, 210, 210));
Painter->drawEllipse(2, 2, 16, 16);
if (_enabled)
{
Painter->setBrush(_lg);
Painter->drawEllipse(3, 3, 14, 14);
}
else
{
Painter->setBrush(_lg_disabled);
Painter->drawEllipse(3, 3, 14, 14);
}
Painter->end();
}
void SwitchButton::SwitchCircle::setEnabled(bool flag)
{
_enabled = flag;
}
Implémentation Python (Prototype; PyQt5)
_ {Usage:
switchbtn = SwitchButton(self, "On", 15, "Off", 31, 60)
(...). py
from PyQt5 import QtWidgets, QtCore, QtGui
class SwitchButton(QtWidgets.QWidget):
def __init__(self, parent=None, w1="Yes", l1=12, w2="No", l2=33, width=60):
super(SwitchButton, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.__labeloff = QtWidgets.QLabel(self)
self.__labeloff.setText(w2)
self.__labeloff.setStyleSheet("""color: rgb(120, 120, 120); font-weight: bold;""")
self.__background = Background(self)
self.__labelon = QtWidgets.QLabel(self)
self.__labelon.setText(w1)
self.__labelon.setStyleSheet("""color: rgb(255, 255, 255); font-weight: bold;""")
self.__circle = Circle(self)
self.__circlemove = None
self.__ellipsemove = None
self.__enabled = True
self.__duration = 100
self.__value = False
self.setFixedSize(width, 24)
self.__background.resize(20, 20)
self.__background.move(2, 2)
self.__circle.move(2, 2)
self.__labelon.move(l1, 5)
self.__labeloff.move(l2, 5)
def setDuration(self, time):
self.__duration = time
def mousePressEvent(self, event):
if not self.__enabled:
return
self.__circlemove = QtCore.QPropertyAnimation(self.__circle, b"pos")
self.__circlemove.setDuration(self.__duration)
self.__ellipsemove = QtCore.QPropertyAnimation(self.__background, b"size")
self.__ellipsemove.setDuration(self.__duration)
xs = 2
y = 2
xf = self.width()-22
hback = 20
isize = QtCore.QSize(hback, hback)
bsize = QtCore.QSize(self.width()-4, hback)
if self.__value:
xf = 2
xs = self.width()-22
bsize = QtCore.QSize(hback, hback)
isize = QtCore.QSize(self.width()-4, hback)
self.__circlemove.setStartValue(QtCore.QPoint(xs, y))
self.__circlemove.setEndValue(QtCore.QPoint(xf, y))
self.__ellipsemove.setStartValue(isize)
self.__ellipsemove.setEndValue(bsize)
self.__circlemove.start()
self.__ellipsemove.start()
self.__value = not self.__value
def paintEvent(self, event):
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
pen = QtGui.QPen(QtCore.Qt.NoPen)
qp.setPen(pen)
qp.setBrush(QtGui.QColor(120, 120, 120))
qp.drawRoundedRect(0, 0, s.width(), s.height(), 12, 12)
lg = QtGui.QLinearGradient(35, 30, 35, 0)
lg.setColorAt(0, QtGui.QColor(210, 210, 210, 255))
lg.setColorAt(0.25, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(0.82, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(1, QtGui.QColor(210, 210, 210, 255))
qp.setBrush(lg)
qp.drawRoundedRect(1, 1, s.width()-2, s.height()-2, 10, 10)
qp.setBrush(QtGui.QColor(210, 210, 210))
qp.drawRoundedRect(2, 2, s.width() - 4, s.height() - 4, 10, 10)
if self.__enabled:
lg = QtGui.QLinearGradient(50, 30, 35, 0)
lg.setColorAt(0, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(0.25, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(0.82, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(1, QtGui.QColor(230, 230, 230, 255))
qp.setBrush(lg)
qp.drawRoundedRect(3, 3, s.width() - 6, s.height() - 6, 7, 7)
else:
lg = QtGui.QLinearGradient(50, 30, 35, 0)
lg.setColorAt(0, QtGui.QColor(200, 200, 200, 255))
lg.setColorAt(0.25, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(0.82, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(1, QtGui.QColor(200, 200, 200, 255))
qp.setBrush(lg)
qp.drawRoundedRect(3, 3, s.width() - 6, s.height() - 6, 7, 7)
qp.end()
class Circle(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Circle, self).__init__(parent)
self.__enabled = True
self.setFixedSize(20, 20)
def paintEvent(self, event):
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
qp.setPen(QtCore.Qt.NoPen)
qp.setBrush(QtGui.QColor(120, 120, 120))
qp.drawEllipse(0, 0, 20, 20)
rg = QtGui.QRadialGradient(int(self.width() / 2), int(self.height() / 2), 12)
rg.setColorAt(0, QtGui.QColor(255, 255, 255))
rg.setColorAt(0.6, QtGui.QColor(255, 255, 255))
rg.setColorAt(1, QtGui.QColor(205, 205, 205))
qp.setBrush(QtGui.QBrush(rg))
qp.drawEllipse(1,1, 18, 18)
qp.setBrush(QtGui.QColor(210, 210, 210))
qp.drawEllipse(2, 2, 16, 16)
if self.__enabled:
lg = QtGui.QLinearGradient(3, 18,20, 4)
lg.setColorAt(0, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(0.55, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(0.72, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(1, QtGui.QColor(255, 255, 255, 255))
qp.setBrush(lg)
qp.drawEllipse(3,3, 14, 14)
else:
lg = QtGui.QLinearGradient(3, 18, 20, 4)
lg.setColorAt(0, QtGui.QColor(230, 230, 230))
lg.setColorAt(0.55, QtGui.QColor(210, 210, 210))
lg.setColorAt(0.72, QtGui.QColor(230, 230, 230))
lg.setColorAt(1, QtGui.QColor(230, 230, 230))
qp.setBrush(lg)
qp.drawEllipse(3, 3, 14, 14)
qp.end()
class Background(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Background, self).__init__(parent)
self.__enabled = True
self.setFixedHeight(20)
def paintEvent(self, event):
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
pen = QtGui.QPen(QtCore.Qt.NoPen)
qp.setPen(pen)
qp.setBrush(QtGui.QColor(154,205,50))
if self.__enabled:
qp.setBrush(QtGui.QColor(154, 190, 50))
qp.drawRoundedRect(0, 0, s.width(), s.height(), 10, 10)
lg = QtGui.QLinearGradient(0, 25, 70, 0)
lg.setColorAt(0, QtGui.QColor(154, 184, 50))
lg.setColorAt(0.35, QtGui.QColor(154, 210, 50))
lg.setColorAt(0.85, QtGui.QColor(154, 184, 50))
qp.setBrush(lg)
qp.drawRoundedRect(1, 1, s.width() - 2, s.height() - 2, 8, 8)
else:
qp.setBrush(QtGui.QColor(150, 150, 150))
qp.drawRoundedRect(0, 0, s.width(), s.height(), 10, 10)
lg = QtGui.QLinearGradient(5, 25, 60, 0)
lg.setColorAt(0, QtGui.QColor(190, 190, 190))
lg.setColorAt(0.35, QtGui.QColor(230, 230, 230))
lg.setColorAt(0.85, QtGui.QColor(190, 190, 190))
qp.setBrush(lg)
qp.drawRoundedRect(1, 1, s.width() - 2, s.height() - 2, 8, 8)
qp.end()
Vous pouvez également le faire avec un contrôle QSlider dans une orientation horizontale allant de 0 à 1. Vous voudrez probablement définir une largeur maximale de 50 environ, afin d'éviter toute extension de la boîte de dialogue. . Vous pouvez ensuite le modifier avec une feuille de style pour améliorer l’apparence ou le sous-classer et dessiner vous-même les contrôles. Cela ne prendra peut-être pas trop de code pour le rendre beau.
Eh bien, vous devrez utiliser QCheckBox . Ce n'est pas un commutateur à bascule, mais il fait la même chose. Si vous voulez vraiment différents visuels, vous devrez créer un widget personnalisé
Davita a raison dans sa réponse en ce qui concerne les cases à cocher. Si vous recherchez quelque chose de similaire au troisième exemple cependant (les commutateurs on/off), vous pouvez simplement utiliser deux QPushButton s pour cela et les définir pour être vérifiable . Faites-les autoexclusive en même temps, et vous devriez être prêt à partir.
Avec un peu de style visuel en utilisant une feuille de style , vous devriez être en mesure de vous rapprocher, sinon de façon ponctuelle.
Voici une implémentation Python 3/PyQt5 de @ - IMAN4K answer .
Améliorations par rapport à l'implémentation d'origine:
from PyQt5.QtCore import QPropertyAnimation, QRectF, QSize, Qt, pyqtProperty
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import (
QAbstractButton,
QApplication,
QHBoxLayout,
QSizePolicy,
QWidget,
)
class Switch(QAbstractButton):
def __init__(self, parent=None, track_radius=10, thumb_radius=8):
super().__init__(parent=parent)
self.setCheckable(True)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self._track_radius = track_radius
self._thumb_radius = thumb_radius
self._margin = max(0, self._thumb_radius - self._track_radius)
self._base_offset = max(self._thumb_radius, self._track_radius)
self._end_offset = {
True: lambda: self.width() - self._base_offset,
False: lambda: self._base_offset,
}
self._offset = self._base_offset
palette = self.palette()
if self._thumb_radius > self._track_radius:
self._track_color = {
True: palette.highlight(),
False: palette.dark(),
}
self._thumb_color = {
True: palette.highlight(),
False: palette.light(),
}
self._text_color = {
True: palette.highlightedText().color(),
False: palette.dark().color(),
}
self._thumb_text = {
True: '',
False: '',
}
self._track_opacity = 0.5
else:
self._thumb_color = {
True: palette.highlightedText(),
False: palette.light(),
}
self._track_color = {
True: palette.highlight(),
False: palette.dark(),
}
self._text_color = {
True: palette.highlight().color(),
False: palette.dark().color(),
}
self._thumb_text = {
True: '✔',
False: '✕',
}
self._track_opacity = 1
@pyqtProperty(int)
def offset(self):
return self._offset
@offset.setter
def offset(self, value):
self._offset = value
self.update()
def sizeHint(self): # pylint: disable=invalid-name
return QSize(
4 * self._track_radius + 2 * self._margin,
2 * self._track_radius + 2 * self._margin,
)
def setChecked(self, checked):
super().setChecked(checked)
self.offset = self._end_offset[checked]()
def resizeEvent(self, event):
super().resizeEvent(event)
self.offset = self._end_offset[self.isChecked()]()
def paintEvent(self, event): # pylint: disable=invalid-name, unused-argument
p = QPainter(self)
p.setRenderHint(QPainter.Antialiasing, True)
p.setPen(Qt.NoPen)
track_opacity = self._track_opacity
thumb_opacity = 1.0
text_opacity = 1.0
if self.isEnabled():
track_brush = self._track_color[self.isChecked()]
thumb_brush = self._thumb_color[self.isChecked()]
text_color = self._text_color[self.isChecked()]
else:
track_opacity *= 0.8
track_brush = self.palette().shadow()
thumb_brush = self.palette().mid()
text_color = self.palette().shadow().color()
p.setBrush(track_brush)
p.setOpacity(track_opacity)
p.drawRoundedRect(
self._margin,
self._margin,
self.width() - 2 * self._margin,
self.height() - 2 * self._margin,
self._track_radius,
self._track_radius,
)
p.setBrush(thumb_brush)
p.setOpacity(thumb_opacity)
p.drawEllipse(
self.offset - self._thumb_radius,
self._base_offset - self._thumb_radius,
2 * self._thumb_radius,
2 * self._thumb_radius,
)
p.setPen(text_color)
p.setOpacity(text_opacity)
font = p.font()
font.setPixelSize(1.5 * self._thumb_radius)
p.setFont(font)
p.drawText(
QRectF(
self.offset - self._thumb_radius,
self._base_offset - self._thumb_radius,
2 * self._thumb_radius,
2 * self._thumb_radius,
),
Qt.AlignCenter,
self._thumb_text[self.isChecked()],
)
def mouseReleaseEvent(self, event): # pylint: disable=invalid-name
super().mouseReleaseEvent(event)
if event.button() == Qt.LeftButton:
anim = QPropertyAnimation(self, b'offset', self)
anim.setDuration(120)
anim.setStartValue(self.offset)
anim.setEndValue(self._end_offset[self.isChecked()]())
anim.start()
def enterEvent(self, event): # pylint: disable=invalid-name
self.setCursor(Qt.PointingHandCursor)
super().enterEvent(event)
def main():
app = QApplication([])
# Thumb size < track size (Gitlab style)
s1 = Switch()
s1.toggled.connect(lambda c: print('toggled', c))
s1.clicked.connect(lambda c: print('clicked', c))
s1.pressed.connect(lambda: print('pressed'))
s1.released.connect(lambda: print('released'))
s2 = Switch()
s2.setEnabled(False)
# Thumb size > track size (Android style)
s3 = Switch(thumb_radius=11, track_radius=8)
s4 = Switch(thumb_radius=11, track_radius=8)
s4.setEnabled(False)
l = QHBoxLayout()
l.addWidget(s1)
l.addWidget(s2)
l.addWidget(s3)
l.addWidget(s4)
w = QWidget()
w.setLayout(l)
w.show()
app.exec()
if __== '__main__':
main()
Voir aussi QRadioButton et QPushButton avec vérifiable et une feuille de style ou un dessin personnalisé peut être créé comme "On/Off bascule"
Je sais que ce fil est ancien, mais j'ai beaucoup lutté avec ce problème particulier malgré le très bon indice de Viv.
Quoi qu'il en soit, je pensais partager la solution que j'avais proposée ici, cela aiderait peut-être quelqu'un d'autre en cours de route.
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);
}
Une petite explication: actionTriggered
sera appelé à chaque fois que le curseur est cliqué ou déplacé avec le clavier. Quand il est traîné, il émettra le signal '7'. Pour éviter la capture immédiate, l'action 7 est bloquée.
En se déplaçant vers la droite, il émet 3 en cliquant et 1 en appuyant sur la touche "droite" (ou "en bas") du clavier, raison pour laquelle nous nous alignons à droite lorsque ce n'est pas un nombre pair.
En se déplaçant à gauche, il émet 2 ou 4.
sliderReleased()
sera appelé une fois que vous aurez relâché le bouton de la souris après l'avoir fait glisser; toutefois, à ce moment-là, le curseur a toujours son ancienne valeur (ce qui m'a un peu déclenché). Donc, afin d’obtenir la bonne position pour faire un accrochage à I interrogé sliderPosition
au lieu de value
et c’est tout.
J'espère que ça aidera quelqu'un.