Qt signal with an enum as a parameter - qt

I'm trying to pass an enum as a value to a slot in my program, but I'm having some problems. In my header file I've created the enum:
Q_ENUMS(button_type);
enum button_type {button_back, button_up, button_down, button_ok};
Q_DECLARE_METATYPE(button_type);
And in my .cpp file I'm trying to pass it to a slot:
QObject::connect(buttons->ui.pushButton_back, SIGNAL(clicked()), this, SLOT(input_handler(button_back)));
But when I compile the code I get:
Object::connect: No such slot main_application::input_handler(button_back) in main_application.cpp:44
Object::connect: (sender name: 'pushButton_back')
Object::connect: (receiver name: 'main_applicationClass')
It compiles and works fine if I don't pass an argument to input_handler.
I've also read that I should be calling qRegisterMetaType, but I can't seem to get the syntax correct. Here's what I tried:
qRegisterMetaType<button_type>("button_type");
but I get this error:
main_application.h:15:1: error: specializing member ‘::qRegisterMetaType<button_type>’ requires ‘template<>’ syntax
Can anyone shed some light on this for me?
Thanks!
Marlon

Signal and Slot need to have the same parameters. What you want is a QSignalMapper.
edit:
Here is an example from an application of mine. It creates 10 menu actions that each are connected to the same slot gotoHistoryPage but each called with a different int value.
m_forwardMenu = new QMenu();
for(int i = 1; i<=10; i++)
{
QAction* action = m_forwardMenu->addAction(QString("%1").arg(i));
m_forwardActions.push_back(action);
m_signalMapper->setMapping(action, i);
connect(action, SIGNAL(triggered()), m_signalMapper, SLOT(map()));
}
ui.forwardButton->setMenu(m_forwardMenu);
connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(gotoHistoryPage(int)));

You're passing the SLOT() macro a value when it's expecting a type. More fundamentally this doesn't make much sense anyway as what you're struggling to achieve is to pass the slot a constant. Why not just use button_back in the slot function directly?
You can define a slot which takes a button_type value, but then you'd need to connect it to a signal that passes one as a parameter.
What are you actually trying to do?

Object::connect: No such slot main_application::input_handler(button_back)
Of course, there is, because signature is main_application::input_handler(button_type), and button_back is a value, not type. And even you make right signature, you will not be able to connect that signal and slot due to their signature mismatch.
Also, you can always use QObject::sender() function to get known, what button was pressed.

Related

Qt: Is emitting signals in lamdas ok or it is bad style (and will it cause problems)

Let's say I have Widget containing a Button and a Spinbox. When the Button is clicked I wish to emit the value of the Spinbox.
I see two possible ways to do this:
Either I can create a private member function
//...
connect(m_Button, &QPushButton::clicked, this, &SomeWidget::emitSpinboxValue);
//...
SomeWidget::emitSpinboxValue() {
emit spinboxValueChanged(m_Spinbox->value());
}
Or I can directly do that in a lambda:
//...
connect(m_Button, &QPushButton::clicked, [this]() { emit spinboxValueChanged(m_Spinbox->value()) });
//...
The lambda way looks neater (since I do not need to create a rather empty member function), but on the other hand seeing that emit in the lambda gives me a bad feeling in my gut.
So, is emitting signals in a lambda ok (and my gut oversensitive), or is it bad style (or do I even set myself up for some unexpected trouble in the future)
It's fine
emit is an empty macro. A signal is a (tool generated) function, and it gets called in the same way as any other function. You've captured this, so you can call any member from the lambda as-if you were in a SomeWidget method.
It is totally fine. However, there is something wrong in your code:
connect(m_Button, &QPushButton::clicked, [this]() { emit spinboxValueChanged(m_Spinbox->value()) });
Must be:
// Important!
// vvvv
connect(m_Button, &QPushButton::clicked, this, [this]() {
emit spinboxValueChanged(m_Spinbox->value());
});
You have to specify the object context for the functor to ensures that the functor will not get invoked if the object does not exist anymore.
See this post for more information.

how to pass qobject as argument from signal to slot in qt connect

My original code passed a QStringList from the signal to the slot and then returned a QList. Everything worked fine but I needed to change both the QStringList and QList into 2 different subclassed QObjects. Since then I have been receiving errors like "synthesized method first required here" or it simply crashes without any error message.
I understand that qt copies all arguments passed in a queued connection and a qobject cannot be copied. So instead of returning a qobject I thought I would create both qobjects prior to emitting the signal. Then I would pass references to each object, modify one of them in the slot function and void the return value. Unfortunately the app still crashes no matter how I code the signal and slot functions. How can I code the signal/slot functions and connect them to either pass both qobjects as arguments or return a qobject?
MyQObject1 obj1("a","b","c");
MyQObject2 obj2();
emit sendSignal(&obj1, &obj2);
// or
MyQObject2 obj2 = emit sendSignal(&obj1);
connect(someObj, SIGNAL(sendSignal(const QObject&)), this, SLOT(receiveSignal(const QObject&)));
The receiveSignal() function does not directly create or modify any qobject. It has to pass the qobjects to another function first which then either modifies obj2 or creates and returns it. Any code examples would be greatly appreciated.
Usually QObject is passed by pointer, not by reference (note that QObject cannot be copied and cannot be passed by value). QObject* is registered as a meta type by default. So creating a signal and a slot with QObject* argument is enough to get them work:
private slots:
void test_slot(QObject* object);
signals:
void test_signal(QObject* object);
Initialization:
connect(this, SIGNAL(test_signal(QObject*)), this, SLOT(test_slot(QObject*)));
Emitting:
QObject* object = new QObject();
emit test_signal(object);
Of course the signal and the slot could be in different classes.

How to pass argument through signal and slots?

My GUI consists of a LineEdit and a PushButton. When the PushButton is clicked, the slot clicked() is called. I want to setup a signal-slot relationship between clicked() as the signal and doSomething() as the slot. The issue is that doSomething() does not have access to the UI and doSomething() relies on the text of LineEdit to work.
I see two solutions:
Grant doSomething() access to the UI.
I want to be able to pass a QString to doSomething() as an argument. clicked() does not accept any arguments. Qsignalmapper might be what I'm looking for. However, it seems like the mapper only passes arguments based on what the signal is. The arguments therefore need to be setup in advance and it seems like it does not help me here.
How would I do solution 2?
Assuming a C++ solution, you might consider using an intermediate signal like the following for #2:
connect(thisWidget, SIGNAL(clicked()),
thisWidget, SLOT(slotClickHandler()));
then:
void slotClickHandler()
{
QString s = "my variable string here";
emit sigDoSomething(s);
}
and them:
void slotDoSomething(const QString &s)
{
// Do something interesting with s here
}
Note that this snippet assumes you've defined a new signal sigDoSomething(const QString &) and a private slot void slotDoSomething(const QString &).

statement cannot resolve address of overloaded function Qt/C++

void RollsRoyceTab::stateRRChanged(int)
{
stateRR = checkBoxRollsRoyce->checkState();
if(stateRR) emit signal_rr_alg; else emit signal_rr_manual;
}
error in stateRR statement cannot resolve address of overloaded function
emit is just syntactic sugar - it doesn't actually do anything and is preprocessed out of the C++ code. What follows emit must be a valid function call, not a signal name.
Change your code to this (assuming no parameters to the signals):
if(stateRR)
emit signal_rr_alg();
else
emit signal_rr_manual();
(Note that a single signal with a boolean or enum parameter could be a bit better - depends on what you connect those signals to though.)

Execute Slot in different class

I want to execute a slot in different class. Is it possible
UI_CDSK Obj;
connect(Obj.penDrive,SIGNAL(clicked()),this,SLOT( Obj.caller()));
This code is in different class and from this class i want to execute slot of different class(UI_CDSK )
Here penDrive and caller belongs to function UI_CDSK class and the mentioned code is in other class
It's a little difficult without knowing the internals of UI_CDSK, but the correct syntax should be:
connect( Obj.penDrive, SIGNAL(clicked()), Obj, SLOT(caller()) );
So long as caller() is a public slot in UI_CDSK.
The connect method takes a pointer as receiver object, so if Obj isn't a pointer to a UI_CDSK object :
connect(Obj.pendrive, SIGNAL(clicked()), &Obj, SLOT(caller()));
Also this is probably already done (otherwise your compiler would have complained), but to use Qt signal slots mechanism, your UI_CDSK class must inherit from QObject.
It looks like the slot doesn't need to be public.

Resources