PDA

View Full Version : Blocksignals for all widgets within a QDialog



muzzled
11th January 2011, 16:43
Hello,

I have a QDialog which contains several widgets. The QDialog is used to display the various properties of a member object of type MyObject.

The QDialog is modeless and can be udated on the fly with a new object using:

void MyDialog::SetMyObject(MyObject* i_pObject)
{
if (m_pObject != i_pObject)
{
m_pObject = i_pObject;

ModelToUI();
}
}

The ModelToUI() function will update every widgets according to the content of m_pObject:

void MyDialog::ModelToUI()
{
if (m_pObject!= NULL)
{
m_pObjectNameEdit->setText(m_pObject->GetName());
[....]
}
}
This is where I am running into a problem, every time the ModelToUI() function is called and setText() is called, it will also launch textChanged signal which I have connected. Then, it will do a bunch of processing for every widgets.

This is what I am trying to avoid. I am aware of the :

m_pObjectNameEdit->blockSignals(true);
m_pObjectNameEdit->setText(m_pObject->GetName());
m_pObjectNameEdit->blockSignals(false);
But I was wondering if there was a way to block ALL signals for every children widgets contained in a dialog without having to use blockSignals for every single on of them. Something I could use in SetMyObject() function just before and after the ModelToUI() call.

I am also aware that in this particular case connecting textEdited instead of textChanged would solve the problem, but I also have a bunch of QRadioButton and QSpinBox widgets.

Any help would be appreciated, thank you!

wysota
11th January 2011, 18:05
Have a flag checked in your custom slots that will prevent the calculations when dialog is updated. Set the flag at the beginning of updating the dialog and clear it after you're done with changes.

muzzled
12th January 2011, 13:40
Have a flag checked in your custom slots that will prevent the calculations when dialog is updated. Set the flag at the beginning of updating the dialog and clear it after you're done with changes.

This is what I somehow ended up doing, thank you.

In case anyone is looking for another solution, I had a partial one which implied looping through every child control and block the signals. However, it was also calling the blockSignals on QGroupBox and QLabel, which was totally useless so I ended up with the solution proposed by wysota.


QList<QWidget *> widgetList = this->findChildren<QWidget *>();
QList<QWidget *>::const_iterator widgetIter (widgetList.begin());
QList<QWidget *>::const_iterator lastWidget (widgetList.end());

while ( widgetIter != lastWidget)
{
(*widgetIter)->blockSignals(true);
++widgetIter;
}

wysota
12th January 2011, 21:58
If you have to block signals then it usually means your design is somehow screwed up.

Zekses
12th October 2011, 16:21
To reduce amount of boilerplate I use the modification of the code here:
http://stackoverflow.com/questions/3556687/prevent-firing-signals-in-qt/3556892#3556892



template<class T>
class QSignalBlocker
{
T * const o;
public:
explicit QSignalBlocker( T * oo )
: o(oo)
{
}
QSignalBlockerCallProxy<T> operator->()
{
if (o)
o->blockSignals( true );
return o;
}
~QSignalBlocker()
{
if(o)
o->blockSignals(false);
}
};

template<class T>
QSignalBlocker<T> SilentCall(T* o)
{
return QSignalBlocker<T>(o);
}

the usage is:


SilentCall(ui.linedit_whatever)->setText(QString("Whatever"));

Only need to wrap the element name with SilentCall()... :)

fix It has been brought to my attention that I misunderstood the necessity of using CallProxy in Stroustrooup's article and that it is unnecessary here :) Simplified.