2013-09-30 9 views
1

사용자 정의 슬라이더 세트 (슬라이더와 연관된 레이블로 구성된 QWidgets)가있는 사용자 정의 QDialog가 있습니다. 본질적으로이 대화 상자는 각 치수의 슬라이더를 조정하여 3D 장면에서 객체의 좌표를 변경하는 데 사용됩니다.매핑 여러 슬라이더가있는 사용자 정의 QWidget의 QSlider :: valueChanged 신호

현재 QDialog 자체는 수정 한 장면 개체에 대한 포인터를 저장합니다. 따라서 슬라이더가 valueChanged을 내보낼 때 객체 이동을 처리하는 슬롯도 QDialog 클래스의 일부입니다. 이동 된 슬라이더를 알 수있는 방법이 없기 때문에 (다소 비효율적 인) 이동 기능은 대화 상자의 모든 슬라이더를 반복하고 값을 수집 한 다음 3D 객체에 새 구성을 지정합니다.

이상적으로 슬라이더를 움직일 때 변경된 치수 만 다시 지정해야합니다. 그래서 QSignalMapper를 사용하여 각 슬라이더를 숫자 인덱스로 식별하려고 시도했습니다. 이렇게하려면 두 개의 매개 변수, 즉 보낸 사람 슬라이더를 식별하는 신호와 새 값 자체를 제공하는 신호를 사용하여 valueChanged 신호를 보낼 수 있어야합니다. 불행히도 here을 배웠으므로 QSignalMapper가이를 수행 할 수 없습니다.

원하는 기능을 얻는 또 다른 방법은 sender() 메서드를 사용하는 것입니다. 그러나 문서에 따르면 이는 나쁜 관행입니다. 모듈성의 원칙을 위반합니다.

다른 해결책 몇 가지를 생각해 볼 수 있습니다. 부모 슬라이스 클래스가 부모 대화 상자를 저장할 수 있도록 허용합니다. (동일하게 나쁜 것 같습니다. sender()이 좋지 않습니다.) 또는 정적 멤버로 이동 가능한 객체 자체를 저장할 수도 있습니다. 전체 대화 상자에서 (정적이 아닌/지금은 그대로) 사용자 정의 슬라이더 클래스.

어떤 방법을 사용하면 가장 좋은 방법일까요? 어떤 대안을 고려해야합니까?

답변

1

가능한 해결 방법은 다음과 같습니다 나는 다음처럼 작성할 것입니다. 값이 걸리면 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()); 
} 
+0

그 접근 방식은 훌륭합니다! 사실, 필자는 필자의 경우 'valueChanged'의 추가 방출이 필요 없다는 것을 발견했다. – nicole

0

나는 sender() 메서드를 사용하는 것이 좋습니다라고 생각합니다. 사용자가 어떤 목록에 포인터로 QSignalMapper map() 저장 슬라이더 ID로, 마우스로 슬라이더를 놓을 때 방출 QSlider 신호 sliderReleased()를 연결

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); 
    } 
} 
1

이상적인 솔루션은 QSlider를 서브 재 방출 추가 파라미터 (X/Y/Z 축)과 valueChanged() 신호하는 것이다. QSlider에서

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) 신호를하고, 축 지수 (0/1/2)로 자신의 신호 valueChanged(int,int)을 방출 :의 주어진 축 지수 (0/1/2)를 구축 MySlider을 가정 해 봅시다. 이제 응용 프로그램에서 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))); 
} 

, 당신은 레이아웃이나 뭔가이 슬라이더를 준비해야합니다. 이 방법의 출처는 Here입니다.

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

이 객체의 스레드와 다른 스레드에서 Qt :: DirectConnection을 통해 슬롯을 호출 할 때 Sender()의 반환 값이 유효하지 않습니다. 이 시나리오에서는이 기능을 사용하지 마십시오. – user2042397