Отображение сигналов QSlider :: valueChanged в пользовательском QWidget с несколькими ползунками

У меня есть собственный QDialog с набором пользовательских ползунков (т.е. QWidgets, каждый из которых состоит из ползунка и соответствующей метки) на нем. По сути, этот диалог используется для изменения координат объекта в 3D-сцене путем настройки ползунков для каждого измерения.

В настоящее время сам QDialog хранит указатель на объект сцены, который он изменяет. Таким образом, слот, который заботится о движении объекта, когда ползунок излучает valueChanged также является частью класса QDialog. Поскольку он не может знать, какой ползунок был перемещен, функция перемещения (довольно неэффективно) просто проходит по всем ползункам в диалоговом окне, собирает их значения и назначает новую конфигурацию трехмерному объекту.

В идеале, только перемещение, которое изменилось, должно быть переназначено при перемещении ползунка. Поэтому я попытался использовать QSignalMapper для идентификации каждого ползунка с помощью числового индекса. Это потребует возможности отправить valueChanged сигнал с двумя параметрами: один идентифицирует ползунок отправителя, а второй сам задает новое значение. К сожалению, как я узнал Вот, QSignalMapper не может этого сделать.

Другой способ получить функциональность, которую я хочу, — это использовать sender() метод. Но, согласно документации, это плохая практика — она ​​нарушает принцип модульности.

Я могу подумать о нескольких других решениях: разрешить пользовательскому классу ползунка сохранять родительский диалог (кажется, плохо в том же сказать, что sender() плохо), или, возможно, даже сохраните сам подвижный объект как статический член пользовательского класса ползунка вместо (не статически / как сейчас) в общем диалоге.

Какой из этих подходов, если таковые имеются, будет лучшим путем? Какие альтернативы я должен рассмотреть?

1

Решение

Возможное решение — подключить сигнал QSlider sliderReleased(), выдается, когда пользователь отпускает ползунок с помощью мыши, с помощью QSignalMapper map() и сохранить идентификатор ползунка с указателем на некоторый список. Когда значение зависло, QDialog может выдать другой сигнал с информацией об идентификаторе слайдера и новом значении.

QSignalMapper *mapper = new QSignalMapper(this);

connect(slider_0, SIGNAL(sliderReleased()), mapper, SLOT(map()));
mapper->setMapping(slider_0, 0);
tab_s[0] = slider_0;
connect(slider_1, SIGNAL(sliderReleased()), mapper, SLOT(map()));
mapper->setMapping(slider_1, 1);
tab_s[1] = slider_1;
connect(slider_2, SIGNAL(sliderReleased()), mapper, SLOT(map()));
mapper->setMapping(slider_2, 2);
tab_s[2] = slider_2;connect(mapper, SIGNAL(mapped(int)),
this, SLOT(checkSlider(int)));

и в каком-то слоте:

void SomeDialog::checkSlider(int id)
{
emit valueChanged(id, tab_s[id]->value());
}
1

Другие решения

Идеальным решением будет подкласс QSlider и переиздать valueChanged() сигнал с добавленными параметрами (ось x / y / z). Скажем MySlider который строит с заданным индексом оси (0/1/2):

class MySlider : public QSlider
{
Q_OBJECT
public:
MySlider(int axis, QWidget *parent);

signals:
void valueChanged(int axis, int value);

private slots:
void reemitValueChanged(int value);

private:
int m_axis;
};

MySlider::MySlider(int axis, QWidget *parent)
: QSlider(parent)
{
m_axis = axis;
connect(this, SIGNAL(valueChanged(int)),
this, SLOT(reemitValueChanged(int)));
}

void MySlider::reemitValueChanged(int value)
{
emit valueChanged(m_axis, value);
}

MySlider перехватывает valueChanged(int) сигнал от QSliderи испускает собственный сигнал valueChanged(int,int) с индексом оси (0/1/2). Ты можешь использовать MySlider в приложении сейчас:

for (int i=0; i<3; i++) {
sliders[i] = new MySlider(i, this);
connect(sliders[i], SIGNAL(valueChanged(int,int)),
this, SIGNAL(updateScene(int,int)));
}

Конечно, вам придется расположить эти ползунки в макете или что-то в этом роде. Вотэто источник этого подхода.

1

Я думаю, используя sender() метод в порядке.
Я бы написал что-то вроде этого:

enum Axes
{
axisX,
axisY,
axisZ
}

class MyDialog : public QDialog
{
...
signals:
void valueChanged(int value, int type);
}

MyDialog::MyDialog(QWidget *parent) :
QDialog(parent)
{
...
connect(xSlider, SIGNAL(valueChanged(int)),
this, SLOT(onSliderChange(int));
connect(ySlider, SIGNAL(valueChanged(int)),
this, SLOT(onSliderChange(int));
connect(zSlider, SIGNAL(valueChanged(int)),
this, SLOT(onSliderChange(int));
}

void MyDialog::onSliderChange(int value)
{
int axis = -1;
QSlider *slider = dynamic_cast<QSlider*>(sender());
if (slider == xSlider)
{
axis = axisX;
}
else if (slider == ySlider)
{
axis = axisY;
}
else if (slider == zSlider)
{
axis = axisZ;
}
else
{
qWarning() << "Wrong sender";
}

if (axis != -1)
{
emit valueChanged(value, axis);
}
}
0

//signalMapper.h
//--------------

#ifndef SIGNALMAPPER_H
#define SIGNALMAPPER_H

#include <QWidget>
#include <QGridLayout>
#include <QSlider>
#include <QLabel>

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = 0);
~Widget();

private:
QGridLayout*    m_pGridLayoutMain;
QLabel*         m_pLabel;

private slots:
void setLabelText(QWidget *pWidget);
};

#endif // SIGNALMAPPER_H//signalMapper.cpp
//----------------

#include "signalMapper.h"#include <QSignalMapper>
#include <QString>

Widget::Widget(QWidget *parent)
: QWidget(parent)
{
setMinimumSize(400, 200);
QSignalMapper* pSignalMapper = new QSignalMapper(this);

m_pGridLayoutMain = new QGridLayout(this);
m_pGridLayoutMain->setContentsMargins(10, 10, 10, 10);
m_pGridLayoutMain->setSpacing(10);

m_pLabel = new QLabel(this);
m_pLabel->setMinimumSize(150, 20);
m_pLabel->setAlignment(Qt::AlignCenter);
m_pLabel->setFrameStyle(QFrame::Box | QFrame::Sunken);
m_pGridLayoutMain->addWidget(m_pLabel, 0, 0);

for(int i=1; i < 10; i++)
{
QSlider* pSlider = new QSlider(this);

QString strObjName = "Slider " + QString().setNum(i);
pSlider->setObjectName(strObjName);
pSlider->setMinimum(0);
pSlider->setMaximum(100);
pSlider->setSingleStep(1);
pSlider->setOrientation(Qt::Horizontal);
pSlider->setValue(35);

connect(pSlider, SIGNAL(valueChanged(int)), pSignalMapper, SLOT(map()));
pSignalMapper->setMapping(pSlider, pSlider);
m_pGridLayoutMain->addWidget(pSlider, i, 0);
}

connect(pSignalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setLabelText(QWidget*)));
}

Widget::~Widget()
{

}

void Widget::setLabelText(QWidget *pWidget)
{
QSlider* pSlider = dynamic_cast<QSlider*>(pWidget);

if(pSlider)
{
qDebug("Success");
m_pLabel->setText(pSlider->objectName()+" value changed to "+QString().setNum(pSlider->value()));
}
else
{
qDebug("Failure");
}
}
0
По вопросам рекламы [email protected]