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

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.)

Related

Use QTest macros (QVERIFY, QCOMPARE, etc.) in function other than the test function

In general, the macros QVERIFY, QCOMPARE, etc. shall not be used outside a test function. The reason is, that in case of a failure, they interrupt the test with a return.
If I want to do tests in a function, I should do them by hand and return false if one of them fails. Then call the function with QVERIFY. But when I do this, I miss out the detailed output of the macros like the line where the error occurred.
So I'm looking for a way to use the macros outside of a test function. One solution is to create my own macro that interrupts the test when a macro call in the underlying function fails. The main problem here is to detect when a test has failed. Looking into Qt's code, in case of a fail the variable QTest::failed is set to true. But I don't have access to this variable.
Is there a way to find out if a QtTest macro has failed?
Yeah, Qt does not really offer anything here because the test will not really get interrupted within your own function. The control flow cannot be as easily disturbed. You would need to throw an exception and make sure it's correctly caught.
What I'm doing now is just returning a const char* (works when using a string literal). If the function actually returns something, std::variant can be used, e.g.:
std::variant<MyObject, const char*> createObject() {
// do some preparations
if(preparationsFail) {
return "Error occurred";
// all worked
// ...: create some myObject
return myObject;
}
void MyTest::testFunction() {
auto result = createObject();
if(const char** error = std::get_if<const char*>(&result)) {
QVERIFY2(false, *error); // we get pointer to value, so type is **
}
// else, work with myObject by std::get<MyObject>(result);
}
Not as concise as would be desired, but it works.
It can be made more beautiful by wrapping const char* and, depending on your style, by using std::visit etc. but that's up to you and your style.

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.

Qt,how does ProcessState enum works

I don't under stand how to use the ProcessState enums. According to documentation, the ProcessState enum can have the following values:
QProcess::NotRunning- 0 - The process is not running.
QProcess::Starting- -1-The process is starting, but the program has not yet been invoked.
QProcess::Running -2 -The process is running and is ready for reading and writing.
How would I use them?
What you refer to are not functions, simply values. You could assign them to an integer and output its value:
int val = QProcess::Starting;
qDebug() << "the value of QProcess::Starting is" << val;
To check the state of a process, you could do:
QProcess *process;
....
if (process->state() == QProcess::Running) // do something with a running process
Of course, when it comes to a QProcess, you really need to be handling signals that the process emits as it changes state. You do not want to do any sort of busy-waiting, and I should discourage the use of any Qt function called waitFor.... Those functions cause the event loop to be re-entered, and potentially to re-enter your code that you never realized could be re-entered. It's a Pandora's box you do not want to open. About the only valid use of wait-style functions is to wait for QThreads that have been quit() to finish before you return from the main() function.
You can have states for the processes to be run. You can then connect your slot to the state changed signal, even in QML if needed, and act accordingly. Also, not that there is no such a thing as "enum function". It is just a simple enumeration that basically the state "property" holds. You can query and set it the usual way. You can see the documentation for those methods below.
http://qt-project.org/doc/qt-5.0/qtcore/qprocess.html#state
http://qt-project.org/doc/qt-5.0/qtcore/qprocess.html#setProcessState
This looks like a generic Qt examples as your question is, but here you go:
myclass.h
class MyClass : QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent);
public Q_SLOTS:
void handleProcessStateChanged(QProcess::ProcessState newProcessState);
....
}
myclass.cpp
...
MyClass::MyClass(QObject *parent)
: QObject(parent)
{
}
MyClass::myProcessInvokeMethod()
{
connect(myprocess, SIGNAL(stateChanged(QProcess::ProcessState), this, SLOT(handleStateChange(QProcess::ProcessState)));
myprocess.start(myprogram, myarguments);
....
}
void MyClass::handleProcessStateChange(QProcess::ProcessState newProcessState)
{
switch (newProcessState) {
case QProcess::NotRunning:
qDebug() << "Here goes the handler code when the process is not yet running";
break;
case QProcess::Starting:
qDebug() << "Here goes the handler code when the process is starting";
break;
case QProcess::Running:
qDebug() << "Here goes the handler code when the process is running";
break;
}
}
...

What's the QMetaCallEvent for and how to access its details?

I have an event filter and I noticed when I click to expand/collapse a tree branch I get QEvent::MetaCall. I was thinking about using this to roll my own expand/collapse code, but I don't know how to get any information, such as the index of the item.
Is there anything available from this MetaCall event type?
I found someone had asked this same question on another site, but without an answer, here:
http://www.qtcentre.org/threads/37525-How-to-filter-QEvent-MetaCall
What is this event typically used for?
The biggest question are: What exactly are you trying to do? What is the Qt class that received those events? As far as I'm concerned, you're trying to do things the hard way, so why bother?
The QMetaCallEvent is the event representing a slot call whenever a queued connection is used to invoke a slot. This might be due to a signal firing that was connected to a slot, or due to the use QMetaObject::invoke or QMetaObject::invokeMethod. The queued connection bit is the important part! Queued connections are not used by default for calls between objects in the same thread, since they have the event queue management overhead, unless either of the two conditions below holds true:
You provide Qt::QueuedConnection argument to QObject::connect or QMetaObject::invoke[Method], or
The receiving object's thread() is different from the thread where the call is originating - at the time of the call.
The QMetaCallEvent event class carries the information needed to invoke a slot. It contains the sender QObject and its signal id (if the call comes from a signal-slot connection), as well as the target slot identifier, and the arguments needed to be passed into the slot.
Thus, you could check if the called slot is the one you wish to intercept, as well as what arguments were passed to it. For example, if you're calling a slot with a single int parameter, then *reinterpret_cast<int*>(metaCallEvent->args()[1]) will give you the value of that integer. The zero-th argument is used for the return value, if any, so the parameters are indexed with base 1.
Disclaimer Since the QMetaCallEvent class is internal to Qt's implementation, you're making your application's binary tied to the particular Qt version in full (entire major.minor version) and you lose the benefits of binary compatibility offered by Qt across the major version. Your code may still compile but cease to work properly when you switch to another minor version of Qt!
The below applies to Qt 5.2.0, I have not looked at any other versions!
So, suppose you want to intercept a call to QLabel::setNum. You'd catch such events as follows:
#include <private/qobject_p.h> // Declaration of QMetaCallEvent
bool Object::eventFilter(QObject * watched, QEvent * event) {
QLabel * label = qobject_cast<QLabel*>(watched);
if (! label || event->type() != QEvent::MetaCall) return false;
QMetaCallEvent * mev = static_cast<QMetaCallEvent*>(event);
static int setNumIdx = QLabel::staticMetaObject.indexOfSlot("setNum(int)");
if (mev->id() != setNumIdx) return false;
int num = *reinterpret_cast<int*>(mev->args()[1]);
// At this point, we can invoke setNum ourselves and discard the event
label->setNum(num);
return true;
}
If you want to see, globally, all slots that are called using the metacall system, you can do that too. Template parametrization of the base class allows flexibility to use any application class - say QCoreApplication, QGuiApplication, QApplication, or a user-derived type.
template <class Base> class MetaCallWatcher : public Base {
MetaCallWatcher(int& argc, char** argv) : Base(argc, argv) {}
bool notify(QObject * receiver, QEvent * event) {
if (event->type() == QEvent::MetaCall) {
QMetaCallEvent * mev = static_cast<QMetaCallEvent*>(event);
QMetaMethod slot = receiver->metaObject()->method(mev->id());
qDebug() << "Metacall:" << receiver << slot.methodSignature();
}
return Base::notify(receiver, event);
}
}
int main(int argc, char ** argv) {
MetaCallWatcher<QApplication> app(argc, argv);
...
}
The QEvent::MetaCall-type event is created whenever a signal has been emitted that is connected to a slot in the receiving QObject. Reacting to this event in a custom filter/event handler seems to circumvent Qt's mightiest feature, the signal-slot architecture. It's probably better to find out which slot is called and if that slot is virtual so you can overload it.
QEvent::MetaCall is used for delivering cross-thread signals.

Qt signal with an enum as a parameter

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.

Resources