How connect a signal from C++ to QML function with parameter - c++

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);
});

Related

Qt not emitting signal

I am newbie, I am trying to emit signal from a header file and catch it in my main class. for this have written this header file :-
KeyBoard.h:-
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include <QObject>
#include <QDebug>
class KeyBoard : public QObject{
Q_OBJECT
public:
KeyBoard();
int keyboard_update(QByteArray recieved_key);
signals:
void keyboard_respoense(QString message);
private:
int level;
int sub_level;
};
#endif
and
KeyBoard.cpp:-
#include "KeyBoard.h"
KeyBoard::KeyBoard()
{
level = 0;
sub_level = 0;
}
int KeyBoard::keyboard_update(QByteArray recieved_key)
{
qDebug() << "recieved key == " << recieved_key;
qDebug() << "button == " << recieved_key.at(8);
emit keyboard_respoense("PRESS ENTER TO SELECT TRAIN");
return 1;
}
In my main class, I am catching my signal like this:-
keyboard = new KeyBoard;
connect(keyboard,SIGNAL(keyboard_respoense(QString message)),this,SLOT(send_to_MBU(QString message)));
but when I call keyboard_update function using this line:-
keyboard->keyboard_update(raw_data_MBU_qb);
It enters in keyboard_update() function but never emits the signal, or may be it emits the signal but I am not able to catch it. So, please tell me what exactly I am missing here.
In connect function, no need to mention parameter names. just declare on argument type. Connect like this:-
connect(keyboard,SIGNAL(keyboard_respoense(QString)),this,SLOT(send_to_MBU(QString)));
To let compiler help you, please update to C++11 or more modern and write
connect(keyboard, &Keyboard::Keyboard_respoense, this, &SnakeCaseClass:send_to_MBU);

Why does adding a function argument cause a SLOT() to be unrecognised?

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.

Cannot connect slots from another class

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()));

How to find out from the slot which signal has called this slot?

I mean if I have many different signals which are connected to the same slot. I saw this question but can't understand the link in the answer. Can you give me simple example?
I think you can use this method:
[protected] int QObject::​senderSignalIndex() const
From Qt documentation:
Returns the meta-method index of the signal that called the currently executing slot, which is a member of the class returned by sender(). If called outside of a slot activated by a signal, -1 is returned.
For signals with default parameters, this function will always return the index with all parameters, regardless of which was used with connect(). For example, the signal destroyed(QObject *obj = 0) will have two different indexes (with and without the parameter), but this function will always return the index with a parameter. This does not apply when overloading signals with different parameters.
Warning: This function violates the object-oriented principle of modularity. However, getting access to the signal index might be useful when many signals are connected to a single slot.
Warning: The return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.
This function was introduced in Qt 4.8.
Here is a small example that I created for you that demonstrates how it works:
#include <QTimer>
#include <QMetaObject>
#include <QMetaMethod>
#include <QCoreApplication>
#include <QDebug>
#include <QObject>
class Foo : public QObject
{
Q_OBJECT
public slots:
void mySlot() {
QMetaMethod metaMethod = sender()->metaObject()->method(senderSignalIndex());
qDebug() << metaMethod.name();
qDebug() << metaMethod.methodSignature();
qApp->quit();
}
};
#include "main.moc"
int main(int argc, char **argv)
{
QCoreApplication coreApplication(argc, argv);
QTimer timer;
Foo foo;
QObject::connect(&timer, &QTimer::timeout, &foo, &Foo::mySlot);
timer.setSingleShot(true);
timer.start(1000);
return coreApplication.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
"timeout"
"timeout()"

QObject::connect() with enum parameters

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.