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