PDA

View Full Version : how can I know which object caused a specific event ?



Hossein
21st October 2015, 07:32
Suppose I have 3 sliders on my form, they all so similar jobs, but with a slight difference based on which category the belong .
So one way is to create lets say 3 event handlers for their slider_move() event and then go on.
the other way which I am interested in, is create one event handler, and make all of these 3 use that.

so the signals must have the objects emitted as well, so that in the slot we can differentiate between multiple different objects

How is this second one achieved ?
how can I get the sender in this scenario?
I checked the signal doesn't have a QObject parameter, and I don't want to re-implement the widgets each time I need such capability)?

Thanks in advance

Radek
21st October 2015, 07:51
Each handler (the "slot" procedure] can call sender() and get a pointer to the object which emitted the just processed signal. sender() returns a QObject * which you dynamic_cast to the real sender class (for example, QSlider). Comparing the pointer to addresses of the possible senders, you get the object which signal is processed. Note: calling sender() outside a handler (for example, in a procedure called by the handler - this is "outside, too) returns nullptr.

Hossein
21st October 2015, 08:17
Each handler (the "slot" procedure] can call sender() and get a pointer to the object which emitted the just processed signal. sender() returns a QObject * which you dynamic_cast to the real sender class (for example, QSlider). Comparing the pointer to addresses of the possible senders, you get the object which signal is processed. Note: calling sender() outside a handler (for example, in a procedure called by the handler - this is "outside, too) returns nullptr.

Thanks this is what I came up with so far:
In form load:

connect(ui->sliderXaxisMin,SIGNAL(sliderMoved(int)),this,SLOT( on_sliders_sliderMoved(int)));
connect(ui->sliderXaxisMax,SIGNAL(sliderMoved(int)),this,SLOT( on_sliders_sliderMoved(int)));
connect(ui->sliderYaxisMin,SIGNAL(sliderMoved(int)),this,SLOT( on_sliders_sliderMoved(int)));
connect(ui->sliderYaxisMax,SIGNAL(sliderMoved(int)),this,SLOT( on_sliders_sliderMoved(int)));
and this is the handler:


void frmCustomNetwork::on_sliders_sliderMoved(int position)
{
QSlider * slider = qobject_cast<QSlider*>(sender());
double value = 0;
double divisor = 0;

if( slider == ui->sliderXaxisMin)
{
value = ui->txtXaxisLower->text().toDouble();
divisor = GetDivisior(value);
ui->txtXaxisLower->setText(QString::number(position/divisor));
}
else if ( slider == ui->sliderXaxisMax)
{
value = ui->txtXaxisUpper->text().toDouble();
divisor = GetDivisior(value);
ui->txtXaxisUpper->setText(QString::number(position/divisor));
}
else if ( slider == ui->sliderYaxisMin)
{
value = ui->txtYaxisLower->text().toDouble();
divisor = GetDivisior(value);
QMessageBox::information(this,"error",QString::number(divisor));
ui->txtYaxisLower->setText(QString::number(position/divisor));
}
else if ( slider == ui->sliderYaxisMax)
{
value = ui->txtYaxisUpper->text().toDouble();
divisor = GetDivisior(value);
ui->txtYaxisUpper->setText(QString::number(position/divisor));
}

}



but the catch is when ever I run the application I get this error :

QMetaObject::connectSlotsByName: No matching signal for on_sliders_sliderMoved(int)

whats wrong with?!

Lesiok
21st October 2015, 08:21
Read about QMetaObject::connectSlotsByName.

Hossein
21st October 2015, 08:39
Read about QMetaObject::connectSlotsByName.

So I have to change the eventHanlders name so that It is not like the pattern shown there .
Thanks a gazillion ;)

yeye_olive
21st October 2015, 09:22
For the record, although the sender()-based solution works, it is considered bad pratice because it breaks modularity.

You can use the QSignalMapper class to "forward" a signal without parameters to a signal with a parameter identifying the sender. In your case this means that you lose the int parameter of the sliderMoved(int) signal, but you can recover it with QAbstractSlider::sliderPosition().

Another solution consists in defining a distinct tiny slot for each slider that just calls a common handler with a pointer to the slider as argument.

Radek
21st October 2015, 09:46
Uff, this seems to be some kind of "VS" trick. The logic of the handler seems to be okay, sliderMoved(int) is a legal QSlider signal (so what "no matching signal?), the name of the slot handler is decided by you. No "special form" is prescribed. Sure, frmCustomNetwork must be a Q_OBJECT and the slot handler should be declared in the frmCustomNetwork class header in the public, private or protected slots section. The connect() calls seem to be okay. Supposing the handler is declared in frmCustomNetwork, the code should run.
In the Creator, you get useful hints when writing connect(). Once you type "SIGNAL(", you get available signals of the signaling class. You should see "sliderMoved(int)" on the list. Once you type "SLOT(", you get available slots of the target class. You should see your signal handler on the list. Selecting from the lists avoids most of errors.