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.
Related
I'm designed a QTableWidget with QPushButton, I would like to connect these buttons with a slot to hide some rows.
I'm using a lambda expression to pass a number of a row. But the compiler doesn't recognized this expression :
connect(this->ui->tableWidget->cellWidget(i,0),&QPushButton::clicked,[this,i]{hideRows(i);});
I have this error:
error: no matching function for call to 'SoftwareUdpater::MainWidget::connect(QWidget*, void (QAbstractButton::*)(bool), SoftwareUdpater::MainWidget::displayTable()::<lambda(int)>)'
The function hideRows(int) is declared as a function. And, as a slot, it doesn't work,
CONFIG += c++11 is added in pro file,
My class MainWidget inherits from QWidget,
Q_OBJECT is added in the header.
So I don't udnerstand why connect() is not recognized by Qt 5.9.1 MinGw 32bit.
Edit: [this,i]() instead of [this](const int i) for the lambda expression
Your connection is wrong. You can't connect a function that doesn't take parameters (clicked()) with a function that takes parameters (your lambda). To verify that this is the case, just do this:
connect(this->ui->tableWidget->cellWidget(i,0),&QPushButton::clicked,[this](){});
And see that it will compile. You have to make your design in such a way that signals and slots are compatible.
Also avoid using lambdas in signals and slots. Read the caveats here.
I was reading your comments on the accepted answer and noticed the root of the problem: This error is being thrown because the effective type of the object — as supplied to QObject::connect; i.e QWidget in your case — does not define the referenced signal QPushButton::clicked.
What likely happened is that the QPushButton pointer was cast into a QWidget and then that pointer was given to connect instead of the original which defines the signal.
Cast the pointer back to a QPushButton * and the error should go away.
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*)) );
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();
I have one c++ class and have one signal in it and want to connect that signal with slot another C++ class. Here is my code
class Data : public QObject
{
Q_OBJECT
public:
static Data *instance(void);
signals:
void sendUserID(const QString& userId);
private:
static Data *s_instance;
};
here is my Slot in another class
void DataDetails::seTUserID(const QString user_id)
{
QAndroidJniObject user_id = QAndroidJniObject::fromString(user_id);
QAndroidJniObject::callStaticMethod<void>("com/user/data/userActivity",
"setUserID",
"(Ljava/lang/String;)V",
user_id.object<jstring>());
}
The idea is to access the value of user_id from Data class to DataDetails class
The connection is trying is
QObject::connect(&s_instance, SIGNAL(sendUserID(uid), this, SIGNAL(setUserID(uid))
any other id to get uid to other class is also fine ..
Generally speaking, when you encounter an issue with QObject::connect...
Make sure you have your declarations in order:
Both classes need the Q_OBJECT macro in their declaration.
Make sure your slot is actually declared as a slot (i.e. is part of a public slot: section).
Because connecting signals and slots just uses character strings evaluated at run-time, it's possible to write absolute nonsense and have it compile. In my experience, errors caused by typos are pretty common.
Always test in an environment where you can see your application's console output. Failed connect calls will usually trigger an error message printed to stderr.
Double-check your method names and signatures. Code will still compile even if you've made a typo!
For debugging, use assertions (e.g. bool c = connect(...); Q_ASSERT(c);) to catch missed connections early.
Alternatively, you can use the QMetaMethod-based version of QObject::connect, introduced in Qt 4.8, to avoid some of these issues.
In your particular case:
You've got a typo in the function declaration: it's called seTUserID but you're using setUserID in the connect call.
You're using variable names, not function signatures, in your signal and slot names. Qt expects to see QObject::connect(&s_instance, SIGNAL(sendUserID(const QString), this, SLOT(setUserID(const QString))
You've got a signal connected to another signal, which is valid but doesn't do what you want (it's usually used to chain stuff like this: SomeChildWidget's signal -> MyClass1's signal -> MyClass2's slot).
Check that seTUserID definition is marked as slot. You are probably calling connect in some Data method (because you are using private member directly). Are you trying to use a ref to a pointer to s_instance O_o? Write sendUserID(const Qstring) (the signature of a signal) rather then sendUserID(uid). The same situation with setUserID. You are trying to connect to this pointer and want to send info to another class!? Use new style of Qt connecting signals and slots (pointers to members), with was introduced in Qt 5. Check for setUserID has written right.
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.