2013-09-30 34 views
1

我有一個自定義QDialog,其中包含一組自定義滑塊(即每個由滑塊和相關標籤組成的QWidgets)。實質上,該對話框用於通過調整每個維度的滑塊來更改3D場景中對象的座標。在具有多個滑塊的自定義QWidget中映射QSlider :: valueChanged信號

目前,QDialog本身存儲一個指向它修改的場景對象的指針。因此,當滑塊發射時,處理物體移動的插槽也是QDialog類的一部分。由於無法知道哪個滑塊被移動,因此移動功能(相當低效)只是循環瀏覽對話框中的所有滑塊,收集其值併爲3D對象分配新配置。

理想情況下,只有移動滑塊時必須重新分配更改的維度。所以我嘗試使用QSignalMapper來標識每個滑塊的數字索引。這需要能夠發送帶有兩個參數的valueChanged信號:一個標識發送器滑塊,另一個給出新值本身。不幸的是,當我學到here時,QSignalMapper無法做到這一點。

獲得我想要的功能的另一種方法可能是使用sender()方法。但是,根據文檔,這是不好的做法 - 它違反了模塊化原則。

我可以想到一些其他解決方案:允許自定義滑塊類存儲其父對話框(看起來很糟糕,也就是說sender()是壞的),或者甚至可以將可移動對象本身存儲爲靜態成員自定義滑塊類代替整個對話框中的(非靜態/現在)。

這些方法中的哪一個(如果有的話)將是最好的方法嗎?我應該考慮哪些替代方案?

回答

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()); 
} 
+0

該方法效果很好!事實上,我發現在我的情況下額外的'valueChanged'發射是不必要的;我可以在我的'checkSlider'版本中進行必要的調整。 – nicole

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); 
    } 
} 
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,並與軸指數(0/1/2)發出自己的信號valueChanged(int,int)。您可以在現在的應用程序中使用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