I have a class as follows:
handler.h:
#ifndef HANDLER_H
#define HANDLER_H
#include <QObject>
class handler : public QObject
{
Q_OBJECT
public:
explicit handler(QObject *parent = nullptr);
~handler();
public slots:
void returnHandler(int input);
};
#endif // HANDLER_H
handler.cpp:
#include "handler.h"
#include "otherclass.h"
handler::handler(QObject *parent) : QObject(parent)
{
}
handler::~handler()
{
}
void handler::returnHandler(int input)
{
otherclass *otherclassPointer = otherclass::getInstance();
otherclassPointer->returnFunction(input);
}
As shown, this is a very simple class, which aims to receive an input and pass the input to a function in an external class ('otherclass'). In my main application ('main.cpp'), I create a QThread, and call the returnHandler slot when the QThread is started, as follows:
main.cpp:
QThread* newThread = new QThread();
handler* handlerPointer = new handler();
handlerPointer->moveToThread(newThread);
connect(newThread, SIGNAL(started()), handlerPointer, SLOT(returnHandler(someInput)));
newThread->start();
The issue I'm having is this:
I'm currently get the following error:
QObject::connect: No such slot handler::returnHandler(someInput) in ../app/main.cpp:100
However, if I remove the int input from the handler class (both the .h and .cpp files), the SLOT() is recognized and called successfully when the QThread is started.
Why does adding an argument cause the slot to no longer be recognized?
EDIT: Following some very informative and appreciated comments/answers below, I've modified the approach as follows:
Create a signal in the handler class, which matches the parameters of the returnHandler slot. E.g. void handlerSignal(int).
Used the handlerSignal() SIGNAL instead of the QThread::started() signal in the connect().
Emit the handlerSignal() once the QThread is started.
`
QThread* newThread = new QThread();
handler* handlerPointer = new handler();
handlerPointer->moveToThread(newThread);
connect(handlerPointer, SIGNAL(handlerSignal(int)), handlerPointer, SLOT(returnHandler(int)));
newThread->start();
emit handlerPointer->handlerSignal(someInput);
Thanks!
Two things:
Qt expects the signal and the slot to have the same parameter types.
In SLOT(), you have to provide types, and not names for the parameters.SLOT(returnHandler(int)) instead of SLOT(returnHandler(someInput))
Qt uses the signals and slots's names and argument list to identify them. I your case, Qt looks for a slot named 'returnHandler' and having only one parameter, from type 'someInput'.
connect takes strings as the identification of the signal & slot to connect. The macros SIGNAL and SLOT stringise their arguments (using the preprocessor functionality for that). The argument to SIGNAL or SLOT must therefore be the function name, with parameter types in the parentheses. You cannot do argument binding with them.
If you need to connect to a nullary signal, you need a nullary slot.
Related
I want to connect a signal which is created by a C++ QObject to a function in a QML item. The signal is the "activated" signal from a QSystemTrayIcon and its argument is ActivationReason (an enum value).
Unfortunately it seems I can't connect a signal with this signature to a slot which seems to only be able to receive QVariant.
In the QML file
function trayIconClicked(reason) { ... }
In the C++ code
QObject::connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), rootObject, SLOT(trayIconClicked(QVariant)));
And this is what I get
QObject::connect: Incompatible sender/receiver arguments
QSystemTrayIcon::activated(QSystemTrayIcon::ActivationReason) --> ApplicationWindow_QMLTYPE_11_QML_60::trayIconClicked(QVariant)
If I completely drop the argument on the slot side, the event calls the function. But then I have no idea what ActivationReason triggred it.
A full working version of the code above is here, except that I can't hand in the reason parameter https://github.com/sturmf/qt_samples/tree/master/trayicon
I now subclassed the QSystemTrayicon and added a slot which emits another signal without the parameter.
#ifndef TRAYICON_H
#define TRAYICON_H
#include <iostream>
#include <QObject>
#include <QSystemTrayIcon>
class TrayIcon : public QSystemTrayIcon
{
Q_OBJECT
public:
explicit TrayIcon(QObject *parent = 0) : QSystemTrayIcon(parent){}
signals:
void triggered();
public slots:
void trayIconActivated(QSystemTrayIcon::ActivationReason reason) {
std::cout << "activated" << std::endl;
if (reason == QSystemTrayIcon::Trigger) {
std::cout << "tiggered" << std::endl;
emit triggered();
}
}
};
#endif // TRAYICON_H
In Qt5 you can connect to an anonymous function, by the way.
QObject::connect(trayIcon
, SIGNAL(activated(QSystemTrayIcon::ActivationReason))
, [=](QSystemTrayIcon::ActivationReason r){
rootObject->trayIconClicked(r);
});
I currently try to write an little application for experiments and more. I write everything in its own file (Menu -> menu.cpp etc.). Now I want to create a menu action, this works but interacting with the action doesnt. Thats what I've done so far:
menu.cpp
#include "menu.h"
#include <QMenuBar>
#include <QMenu>
#include <QAction>
void Menu::setupMenu(QMainWindow *window) {
QMenuBar *mb = new QMenuBar();
QMenu *fileMenu = new QMenu("File");
QAction *newAct = new QAction("New...", window);
window->connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
fileMenu->addAction(newAct);
mb->addMenu(fileMenu);
window->setMenuBar(mb);
}
void Menu::newFile() {
printf("hello world!");
}
menu.h
#ifndef MENU_H
#define MENU_H
#include <QObject>
#include <QMainWindow>
#include <QWidget>
#include <QMenuBar>
class Menu : public QObject
{
public:
void setupMenu(QMainWindow *window);
private slots:
void newFile();
};
#endif // MENU_H
But its not printing out 'hello world', the only message I get is:
QObject::connect: No such slot QObject::newFile() in ../from Scratch written UI app C++/src/ui/menu.cpp:11
What can I do to fix this?
~ Jan
class Menu : public QObject
Menu is a QObject but is also needs to use the Q_OBJECT macro.
See the Qt5 - QObject documentation:
The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.
Next, there is some confusion in your connect call. Here is the signature of the static connect function.
Qt5 - static QObject::connect:
QObject::connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection)
You can see it takes 5 parameters (object pointer, signal, object pointer, signal/slot) and the 5th parameter is defaulted.
There is also a member function connect.
Qt5 - QObject::connect:
QObject::connect(const QObject * sender, const char * signal, const char * method, Qt::ConnectionType type = Qt::AutoConnection) const
This takes 4 parameters (object pointer, signal, signal/slot) and the 4th parameter is defaulted.
Your code:
window->connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
You're calling the the connect member function of window but you're passing parameters for the static connect function.
What can I do to fix this?
Figure out what you're trying to do and make the appropriate call.
For example: connect the QAction signal to a slot in Menu then either call the static function as follows.
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
Or using the member function.
connect(newAct, SIGNAL(triggered()), SLOT(newFile()));
I'm writing a program that send an UDP frame every 10 mS. Here's how my program is supposed to work :
I've got a client class :
//Constructor
clientSupervision::clientSupervision()
{
}
void clientSupervision::sendDataUDP(){
//Create a frame and send it
...
}
void clientSupervision::sendDataUDPTimer(int timer){
QTimer *tempsEnvoieTrameSupervision = new QTimer();//Create a timer
tempsEnvoieTrameSupervision->setInterval(timer);//Set the interval
//Mise en place des connections
QObject::connect (tempsEnvoieTrameSupervision,SIGNAL (timeout()),this, SLOT (envoiTrameSupervision())); //Connect the timer to the function
tempsEnvoieTrameSupervision->start();// Start the timer
}
//Call sendDataUDP
void clientSupervision::envoiTrameSupervision(){
std::cout << "Envoi de la trame de supervision";
sendDataUDP();
}
My header file of clienSupervision.h :
#ifndef CLIENTSUPERVISION_H
#define CLIENTSUPERVISION_H
#include <winsock2.h> // pour les fonctions socket
#include <cstdio> // Pour les Sprintf
#include "StructureSupervision.h"
#include "utilitaireudp.h"
#include <QTimer>
#include <QObject>
#include <iostream>
class clientSupervision
{
Q_OBJECT
public:
clientSupervision();
void sendDataUDP();
void sendDataUDPTimer(int timer);
public slots:
void envoiTrameSupervision();
};
#endif // CLIENTSUPERVISION_H
Then I use this in my main :
int main(int argc, char *argv[])
{
clientSupervision c;
c.sendDataUDPTimer(10);
QCoreApplication a(argc, argv);
return a.exec();
}
I've got the error :
no matching function for call to 'QObject::connect(QTimer*&, const char*, clientSupervision* const, const char*)
I don't understand why the connect function can't find a matching function.
What should I change?
There can be several reasons for the issue in general:
You do not inherit QObject.
You do not have the Q_OBJECT macro in your class.
You do not define the method as slot in your header file where the class is declared.
Your issue is the first which can be seen here:
class clientSupervision
You should change your code to:
class clientSupervision : public QObject
// ^^^^^^^^^^^^^^^^
Of course, the constructor implementation and signature would need to change, too, as follows:
explicit clientSupervision(QObject *parent = Q_NULL_PTR) : QObject(parent) { ... }
In addition, you seem to leak your QTimer instance as it does not get the parent as a parameter to the constructor.
Furthermore, the QObject:: scope is needless in your code as your class ought to inherit QObject directly or indirectly either way.
Even more, I would highly encourage you to utilize the new signal-slot syntax.
Another possible cause of this error is trying to connect to a slot which is overloaded. For example, this well cause the same error
QObject::connect(this,
&MazeWidget::MyUpdate,
this,
&QWidget::update,
Qt::QueuedConnection);
But not if you explicitely cast:
QObject::connect(this,
&MazeWidget::MyUpdate,
this,
static_cast<void (QWidget::*)()>(&QWidget::update),
Qt::QueuedConnection);
Here's another one that snuck up on me: The class of the slot object had been forward declared in the header, but not defined in the implementation by including its header.
If none of the answers above worked, check if you have assigned correct object to the signals and the slots. You will get this error when the signals and slots are valid and refer to one object but the object assigned to that signal and slot is different.
I'm trying to use QObject::connect() with enum parameters. I got this message...
QObject::connect: Incompatible sender/receiver arguments
Calendar::calendarExceptionThrown(Calendar*,ExceptionType)
--> CalendarDBView::handleCalendarException(Calendar*,Calendar::ExceptionType)
The connect code is:
connect(cal, SIGNAL(calendarExceptionThrown(Calendar*,ExceptionType)),
this, SLOT(handleCalendarException(Calendar*,Calendar::ExceptionType)));
From what I've read, I figured I needed to add this to the class definition of Calendar:
Q_ENUMS(ExceptionType)
I added this to main.cpp:
qRegisterMetaType<Calendar::ExceptionType>("ExceptionType");
I'm still getting the warning message. This related thread didn't solve my issue. What am I doing wrong?
I believe if you simply change ExceptionType to Calendar::ExceptionType in the SIGNAL part of your connect, it will fix the problem. moc expects the strings for both the SIGNAL and SLOT to match.
You need to be very consistent with your signal and slots declarations, and with what you put in the SIGNAL and SLOT macros. moc isn't a full C++ compiler, it's just a relatively smart parser. But ultimately the signal and slot names are just strings.
For example, this "works":
#include <QtCore>
class A: public QObject {
Q_OBJECT
public:
enum MyEnum { e0 };
public:
A(QObject *parent=0): QObject(parent) {
connect(this, SIGNAL(fire(A::MyEnum)), this, SLOT(foo(A::MyEnum)));
}
public slots:
void foo(A::MyEnum) {
qDebug() << "In slot A::foo()";
}
signals:
void fire(A::MyEnum);
public:
void test() { emit fire(e0); }
};
It would also work if you remove all the A:: qualifiers for MyEnum. But it will fail if you leave some in but remove others.
So qualify all the names if these signals/slots need to be visible/accessible outside your class.
I'm new to development with Qt and our design uses the has-a relationship in a couple of places. In some of these cases the container should expose the signal of the internal object, and then I've currently written a private slot for each such signal, where I in practice re-emit the signal again. Is there some short-cut available in Qt that aids in exposing the signal of the internal object on the container?
You don't have to create a slot for reemiting the signal, you could connect a signal with another signal. This way you will avoid the slot definition.
So in your container you would have something like this:
connect(object, SIGNAL(signal1()), this, SIGNAL(signal1()));
Of course you have to redefine the signal on your container.
For more details check the signal slot documentation
From the documentation:
You can connect as many signals as you want to a single slot, and a signal can be connected to as many slots as you need. It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)
The following is legal:
connect(sender, SIGNAL(originalSignal()), SIGNAL(newSignal()));
The re-emitting of Signals also allows re-emitting multiple signals.
testclass.h:
#include <QObject>
#include <QDebug>
class TestClass : public QObject
{
Q_OBJECT
public:
explicit TestClass(QObject *parent = 0)
{
connect(this, SIGNAL(signal1()), this, SIGNAL(signal2()));
connect(this, SIGNAL(signal1()), this, SIGNAL(signal2()));
connect(this, SIGNAL(signal2()), this, SLOT(slot()));
}
void emitSignal1()
{
emit signal1();
}
signals:
void signal1();
void signal2();
public slots:
void slot()
{
qDebug() << "SLOT HAS BEEN CALLED";
}
};
main.cpp:
#include <QCoreApplication>
#include "testclass.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TestClass instance;
instance.emitSignal1();
return a.exec();
}
The result is that the slot is called twice in this case.
If it is internal structure of your class, why won't you make it friend class. Then you can inside your internal structure call directly emit parentObj->signal()