我有一个自定义QDialog,上面有一组自定义滑块(即QWidgets,每个滑块都包含一个滑块和一个相关的标签)。实质上,此对话框用于通过调整每个维度的滑块来更改3D场景中对象的坐标。
目前,QDialog本身存储一个指向它修改的场景对象的指针。因此,当滑块发出valueChanged
时,处理对象移动的槽也是QDialog类的一部分。由于无法知道哪个滑块被移动,因此移动功能(相当低效)只是遍历对话框中的所有滑块,收集它们的值,并为3D对象分配新配置。
理想情况下,只有在移动滑块时才需要重新分配更改的尺寸。所以我尝试使用QSignalMapper来识别带有数字索引的每个滑块。这需要能够发送带有两个参数的valueChanged
信号:一个标识发送方滑块,另一个给出新值。不幸的是,当我学习here时,QSignalMapper无法做到这一点。
获得我想要的功能的另一种方法可能是使用sender()
方法。但是,根据文档,这是不好的做法 - 它违反了模块化原则。
我可以想到其他一些解决方案:允许自定义滑块类存储其父对话框(看起来很糟糕,sender()
是坏的),或者甚至可以将可移动对象本身存储为自定义滑块类的静态成员,而不是整个对话框中的(非静态/现在)。
这些方法中哪一个(如果有的话)是最好的方式?我应该考虑哪些替代方案?
答案 0 :(得分:1)
可能的解决方案是连接QSlider信号sliderReleased()
,当用户使用鼠标释放滑块时发出,使用QSignalMapper map()
并在某些列表中存储带指针的滑块id。当值挂起时,QDialog可以发出另一个信号,其中包含滑块ID和新值的信息。
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 :(得分:1)
理想的解决方案是子类QSlider
并使用添加的参数(x / y / z轴)重新发出valueChanged()
信号。假设使用给定轴索引(0/1/2)构造MySlider
:
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)
的{{1}}信号,并使用轴索引(0/1/2)发出自己的信号QSlider
。您现在可以在应用程序中使用valueChanged(int,int)
:
MySlider
当然,你必须在布局或其他东西中安排这些滑块。 Here是这种方法的来源。
答案 2 :(得分:0)
我认为使用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);
}
}
答案 3 :(得分: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");
}
}