QObject::connect: signal not found - c++

I have a MainWindow class which is declared in mainwindow.h and defined in mainwindow.cpp respectively like this:
In mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
...
void addNewTab(QString fullFilePath, QString textString="");
public slots:
void disableMenuItem();
...
private:
...
};
In mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
...
connect(this, &MainWindow::addNewTab, this, &MainWindow::disableMenuItem);
...
}
void MainWindow::addNewTab(QString fullFilePath, QString textString)
{
...
}
void MainWindow::disableMenuItem()
{
...
}
Everything compiles and run fine except for the following message on the console:
QObject::connect: signal not found in MainWindow
The message come from the connect call in the constructor above. What does that message mean in my case, and where am I doing wrong?

As drescherjm and Learner mentioned, you forgot to add a signals: section to your header file, and declare your signal within it.
Qt connects signals to slots at runtime, not at compile time, so mis-connected signals and slots cannot be detected until the program is actually run; that's why this problem is reported when it is.
Qt uses the moc preprocessor to turn signals and slots into standard c++, so that's why the signals: and slots: sections of your header will not cause problems when compiling.
Signals are fully defined by moc, so you do not need to define them in your .cpp file, but they still need to be in the header so moc knows to create them.
EDIT:
It appears that you are trying to use a signal with the name of one of your class functions. I don't think that's going to work. the documentation for the new signal/slot syntax indicates that you can connect TO anything, it doesn't have to be a slot, but I believe you still need to define your signal as a signal.

Related

enums and enum classes in Qt Queued Slots

Following advice from Qt documentation and this question's answers, I have code structured like so:
emulator.h:
class Emulator : public QObject
{
Q_OBJECT
public:
enum HaltCause {
Breakpoint,
ReadWatch,
WriteWatch,
UserHalted,
Reset,
SingleStep,
};
Q_ENUM(HaltCause)
...
signals:
void emulationHalted(HaltCause cause);
...
};
My MainWindow class has a matching slot:
private slots:
...
void onEmulationHalted(Emulator::HaltCause cause);
In mainwindow.cpp, the constructor contains:
...
qRegisterMetaType<Emulator::HaltCause>();
...
and in a method invoked later on in the MainWindow class:
...
connect(m_emulator, &Emulator::emulationHalted, this, &MainWindow::onEmulationHalted);
...
The Emulator class is threaded, so the connection between its signal and MainWindow's slot is queued.
Regardless of seemingly following all the guidelines for getting something into Qt's meta-object system, I still get this debug message when the Emulator's thread emits the signal:
QObject::connect: Cannot queue arguments of type 'HaltCause'
(Make sure 'HaltCause' is registered using qRegisterMetaType().)
I've tried this with Enumeration::HaltCause being both a simple enum and a strongly-typed enum class. Both yield the same results.
What am I missing?
Turns out the unqualified HaltCause used in the declaration of Emulator's slot confused the meta-object system. The resolution was to change
signals:
void EmulationHalted(HaltCause cause);
to
signals:
void EmulationHalted(Emulator::HaltCause cause);
in the Emulator declaration (emulator.h).

C++ Qt4: Add slot with QObject implementation

I'm fairly new to Qt in general, and I would like to use some degree of reflection in writing a generic method for printing lists of objects.
I'm currently trying to hook up to the ui like so:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <algorithm>
#include <QStringListModel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
...
connect(ui->print_books_btn, SIGNAL(released()), this, SLOT(PrintList(BookList)));
connect(ui->print_clients_btn, SIGNAL(released()), this, SLOT(PrintList(ClientList)));
}
...
void MainWindow::PrintList(QList<QMetaObject*> list)
{
list.first()->className();
}
My relevant header files look like so:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
...
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
...
private:
Ui::MainWindow *ui;
QList<Book*> BookList;
QList<Client*> ClientList;
private slots:
...
void PrintList(QList<QMetaObject*> list);
};
#endif // MAINWINDOW_H
I believe I've set everything up with regards to the Q_OBJECT macro in the header files:
...
class Book : public QObject
{
Q_OBJECT
public:
Book();
...
}
Everything compiles without error, though when running I get this in the console:
QObject::connect: No such slot MainWindow::PrintList(BookList) in ..\LibraryManager\mainwindow.cpp:18
QObject::connect: (sender name: 'print_books_btn')
QObject::connect: (receiver name: 'MainWindow')
QObject::connect: No such slot MainWindow::PrintList(ClientList) in ..\LibraryManager\mainwindow.cpp:19
QObject::connect: (sender name: 'print_clients_btn')
QObject::connect: (receiver name: 'MainWindow')
Is it possible to work it this way?
Thanks!
UPDATE
I think its QMetaObject that I actually want to be using - so I can do list.first()->className() etc. Edited above ^
UPDATE 2
Required to be using Qt4.
released() signals of QPushButtons would not send any parameters like QMetaObject* as you like to your slots SLOT(PrintList(...))
so your implementation is wrong,
you should think another way for example you take the released() [or clicked()] signals of QPushButtons and connect them to another slot in your class like buttonsClicked() then in the implementation of buttonsClicked() slot you should manually emit a signal with parameters like booklist or clientlist as you like to be received in the other slot PrintList(QMetaObject*)
this is how signals and slots are working in Qt. Slots only receive parameters emitted by signal not any other parameters.
I think you should connect both signals to SLOT(PrintList(QList<QObject*>))).
In the PrintList(QList<QObject*> list) you can use dynamic_cast to check what type it is (BookList or ClientList) then you can print what you want depend on its type.
In Qt5, you can use lambda functions in the QObject::connect method to pass a parameter to your slot:
connect(ui->print_books_btn, &QPushButton::clicked, [=] { PrintList(BookList); });
You can also use the QSignalMapper class to do the same thing in Qt4 (see the doc). Or, you can create two specific slots:
connect(ui->print_books_btn, SIGNAL(released()), this, SLOT(printBookList));
void MainWindow::printBookList()
{
printList(bookList);
}
The last solution is maybe the best way: it's explicit and more readable.

QObject::connect: No such signal

I need to know what am I doing wrong.
I tried researching about it but I can't really find anything that it's related to my case. I am new to QT and debugging signal and slots is kinda technical for me.
What I wanted to do is just simple: make a thread that will continuously send signal to my QProgressBar widget.
Here's my essential code snippets:
thread.h
class MyThread : public QThread
{
public:
MyThread(QWidget * parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
MyThread * test = new MyThread(this);
connect(test,SIGNAL(valueChanged(int)),ui->progressBar,SLOT(setValue(int)));
test->start();
}
thread.cpp
MyThread::MyThread(QWidget * parent)
{
}
void MyThread::run(){
emit valueChanged(10); //for simplicity
}
void MyThread::valueChanged(int value){
}
I only have a single progressBar on my UI and my main is the same as the default.
Anyway, upon running of the code. I kept on getting this no such signal from my thread class. May I know what am I doing wrong?. I would also like to clarify if my understanding is right regarding signals and slots in my own words: it means that the slot will be triggered everytime the signal is called.
I believe the error message is due to a missing Q_OBJECT macro at the top of your MyThread declaration. The documentation at http://doc.qt.io/qt-5/signalsandslots.html explains this is necessary for any class that wants to declare signals and slots.
Change your class definition to:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QWidget * parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
};
Take a look at the linked documentation, specifically the A Small Example section, for a complete explanation why this is needed.
You must not implement a signal in a .cpp file. MOC will do that and there must only be one implementation.
Just delete this part:
void MyThread::valueChanged(int value){
}
If your code works, that might be luck because the linker throws away the right implementation. You should not rely on that.

Subclass of QEditLine with a new SIGNAL

I am trying to subclass QEditLine so that I can define a new SIGNAL that sends an object identifier. At the moment, I connect a parent signal to a slot in the new class and from that slot I emits a proper new signal with the additional object identifier.
I cannot understand one thing. The problem is I don't know how to define a new signal function itself. I don't know what I should put there. I mean I know its arguments but I don't know what it shpould do as a function. I am doing this for the first time and it may looks very silly ;p but I really stuck there >.<.
Can anybody please provide some clues. It is probably a very easy problem.
Thanks
// myqeditline.h
#ifndef MYQEDITLINE_H
#define MYQEDITLINE_H
#include <QWidget>
#include <QLineEdit>
#include <QString>
class MyQEditLine : public QLineEdit
{
Q_OBJECT
public:
explicit MyQEditLine(const QString& n, QWidget *parent = 0);
protected:
QString name;
signals:
void textChanged(QString textCHanged, QString sender);
protected slots:
public slots:
void myTextChanged(QString textChanged);
};
#endif // MYQEDITLINE_H
// myqeditline.cpp
#include "myqeditline.h"
MyQEditLine::MyQEditLine(const QString &n, QWidget *parent)
: QLineEdit(parent),name(n) {
connect(this,SIGNAL(textChanged(QString)),this,SLOT(myTextChanged(QString)));
}
void MyQEditLine::myTextChanged(QString textChanged) {
emit textChanged(QString textChanged, QString name);
}
I just realised that the answer to my question is on this Qt Project website, in section regarding "Signals", in 4th paragraph. It says: "Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void)."

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.