Qt signal mapping - c++

I understand that we could use QSignalMapper to collect a set of parameterless signals, and re-emit them with integer, string or widget parameters corresponding to the object that sent the signal.
But could we do the reverse?
For example, is it possible to achieve:
connect(control,startVehicle(0),vehcileList[0],startReceived());
connect(control,startVehicle(1),vehcileList[1],startReceived());
connect(control,startVehicle(2),vehcileList[2],startReceived());
instead of having 3 different signals from control as
startVehicle_1();
startVehicle_2();
startVehicle_3();

There is a simpler way:
connect(control, SIGNAL(startVehicle(int)), this, SLOT(startReceived(i)));
//in startReceived(i) slot
vehcileList[i]->startReceived();

Related

connecting a basic signal mousepress

I am using QCustomPlot where I am trying to write a code that will rescale my axes once the user press the mouse and drags. I did:
connect(ui->plot, SIGNAL(mousePress(QMouseEvent *event)), this, SLOT(mousedrag(QMouseEvent*)));
and I keep getting:
QObject::connect: No such signal QCustomPlot::mousePress(QMouseEvent
*event)
But mouseWheel(QWheelEvent*) and both mouseWheel and mousePress have signals declared in the QCustomPlot library.
Where am I going wrong? Also if someone has a better signal to trigger my function mousedrag(QMouseEvent*) which rescales the the y2 axis according to y1 axis I am open for suggestions.
The signal signature passed to connect is invalid. The parameter names are not a part of the signature. You should also remove any whitespace so that connect doesn't have to normalize the signatures. A normalized signature has no unnecessary whitespace and outermost const and reference must be removed, e.g. SIGNAL(textChanged(QString)), not SIGNAL(textChanged(const QString &)).
remove
vvvvv
connect(ui->plot, SIGNAL(mousePress(QMouseEvent *event)), this,
SLOT(mousedrag(QMouseEvent*)));
Do the below instead:
// Qt 5
connect(ui->plot, &QCustomPlot::mousePress, this, &MyClass::mousedrag);
// Qt 4
connect(ui->plot, SIGNAL(mousePress(QMouseEvent*)), SLOT(mousedrag(QMouseEvent*));
Sidebar
TL;DR: This sort of API design is essentially a bug.
Events and signal/slot mechanism are different paradigms that the QCustomPlot's design mangles together. The slots connected to these signals can be used in very specific and limited ways only. You have to use them exactly as if they were overloads in a derived class. This means:
Each signal must have either 0 or 1 slots connected to it.
The connections must be direct or automatic to an object in the same thread.
You cannot use queued connections: by the time the control returns to the event loop, the event has been destroyed and the slot/functor will be using a dangling pointer.
When using the "old" signals/slot connection syntax, i.e. the one using the SIGNAL and SLOT macros in the connect() statement, you shall not provide the names of the parameters, only their types.
In other words:
SIGNAL(mousePress(QMouseEvent *event)) // WRONG, parameter name in there!
SIGNAL(mousePress(QMouseEvent *)) // GOOD
SIGNAL(mousePress(QMouseEvent*)) // BETTER: already normalized
So simply change your statement to
connect( ui->plot, SIGNAL(mousePress(QMouseEvent*)),
this, SLOT(mousedrag(QMouseEvent*)) );

How to determine which widget triggered the slot function?

I have an array of 10 objects, each having 8 parameters, all represented in GUI. I'd rather not have 80 slots defined; I'd much prefer to have 1 slot handling all the GUI triggered changes:
// Connect 10 Term objects
for( int n = 0; n < m_MaxTerms; ++n )
{
// Connect several checkboxes for the nth Term item
connect(m_Term[n].m_CD.GetData(), SIGNAL(clicked(bool)), this, SLOT(UpdateTerm()));
// Connect several edit fields for the nth Term item
connect(m_Term[n].m_Volume.GetData(), SIGNAL(editingFinished()), this, SLOT(UpdateTerm()));
...
}
When UpdateTerm() is called I need to update the corresponding data based on the changes in the widget that triggered it. But how could I tell, from within UpdateTerm(), what widget triggered it? One way to solve the problem is to update data from all widgets when the slot is triggered by any of them. However, this is very inefficient; updating only the changed item would be much preferred.
Thus the question: is it possible from the slot function to determine which of the widgets triggered it? What would be the cleanest method of doing so?
You can use the QObject::sender() function to determine which object emitted the signal. This function is documented here.

Map QWidget to variable

The idea was to connect QWidget with a variable so that when text changes on a widget it will be also changed in a variable.
And do this with just one line like this
WidgetMapper::connect(ui->lineEdit, SIGNAL(textChanged(QString)), someClass.var);
which would connect for example QLineEdit with a variable.
1) This would display var in a lineEdit
2) when lineEdit fires an textChanged(QString) signal - WidgetMapper would convert this QString to correct mapped type with stringstream and write it to var.
But i dont really know templates that well, and dont know if it is possible at all.
I dont think it is possible to use one WidgetMapper for every type, so i also tried creating separate instances for each type (WidgetMapper<int> mapper;) which would still be betten then writing setters and onTextChangedSlots for each QLiteEdit but i could not figure out how to make it work as well (converter part still could not figure out the correct type).
WidgetMapper is using QSignalMapper to map signal to QWidget, and it worked fine, the part i have troubles with - is converting QString to template variable.
So is it possible? And if yes how could i do this? Or maybe there already a solution for this problem? (Somehow use QDataWidgetMapper with a class that contains variables maybe?)
First of, connecting the variable would do nothing else than calling some function if it were possigle.
Second try using QSignalMapper, this way you could use a single slot for all widgets, given you keep their pointers in an array with the index being the signal(int) emitted by the SignalMapper. This way your slot can just use MyWidgetArray[i]->text().

Connect signals to slots with constant values

To connect signals to slots, as far as I know, the parameters of the signal need to match the parameters of the slot. So for example:
connect(dockWidget->titleBarWidget(), SIGNAL(closeButtonClicked()), ui->sideControls, SLOT(closeDockWidget()));
But what if I want to have a signal call a slot that has a different amount of parameters, but always pass a constant value into the slot. For example, using the above piece of code:
connect(dockWidget->titleBarWidget(), SIGNAL(closeButtonClicked()), ui->sideControls, SLOT(setDockWidget(false)));
Or in other words, whenever the button is pressed, it calls the setDockWidget() function with the false parameter. Is this possible?
You can use lambda with desired call with constant argument. Example:
connect(obj, &ObjType::signalName, [this]() { desiredCall(constantArgument); });
More about new connect syntax: https://wiki.qt.io/New_Signal_Slot_Syntax.
No, it is not possible. You are only allowed to connect slots with less or equal argument count, than in corresponding signal. (see documentation)
You have to create proxy slot, that will call desired one.
In a way, yes, you can. But it's not very powerful : just declare the setDockWidget this way :
[virtual] void setDockWidget(bool state=false) ;
And declare the connection this way :
connect(emitter, SIGNAL(closeButtonClicked()), receiver, SLOT(setDockWidget()));
setDockWidget called without arguments take the default ones.

Qt slot with default argument

I have a block of spin controls which change individual elements of an array
Rather than having separate receiver slot functions, I wanted to just specify which control sent the message in the signal
You can do this with a QSignalMapper - but is there anyway of doing it simply as below?
spin0 = new QDoubleSpinBox;
connect(spin0,SIGNAL(valueChanged(double)),this,SLOT(handler(0,double));
spin1 = new QDoubleSpinBox;
connect(spin1,SIGNAL(valueChanged(double)),this,SLOT(handler(1,double));
....
private slot:
void handler(int element,double value);
From any slot handler you can can use sender() to get a pointer to the object that sent the signal. Then you can use the objectName() property to communicate any further identifying information.
I don't believe so, at least not using that syntax ... the SIGNAL and SLOT macros turn their arguments into strings which are then parsed and used by the Qt runtime to look-up the associated functions and/or class methods in the tables created by moc during the pre-processing phase of compilation. So if you encoded a default argument into the SLOT macro, then that's not a valid function signature that can be used by Qt for run-time lookup of the actual slot function in the moc-generated function tables.