The title might be hard to understand, sorry for that.
I have problem connection signal to slot. There are no compile errors, but the connect returns false.
There is error line printed in the console:
QObject::connect: No such slot QObject::clientConnected_() in ../server/server.cpp:8
I think the problem is that connect does not see the slot clientConnected_() in the class Server. Or maybe looks for it in class QObject for some reason.
Code is as follows:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QtNetwork>
#include <QTcpServer>
#include <QObject>
class Server : public QObject
{
Q_OBJECT
public:
bool startListening(const quint16 port);
public slots:
static void clientConnected_();
private:
QTcpServer * server_;
};
#endif // SERVER_H
server.cpp
#include "server.h"
#include <iostream>
bool Server::startListening(const quint16 port)
{
server_ = new QTcpServer();
QObject::connect(server_,SIGNAL(newConnection()),this,SLOT(clientConnected_()));
return server_->listen(QHostAddress::Any,port);
}
void Server::clientConnected_()
{
std::cout << "Connection established!" << std::endl;
return;
}
Any ideas?
static void clientConnected_();
change to
private slots:
void clientConnected_();
As was mentioned, youd should decalre your 'void clientConnected_()' as a non-static (you can't connect to static member, but if you want you can call static method from your slot). And also you have to declare slots in 'slot' section to make MOC able to parse your slots.
More information you can find here http://doc.qt.io/qt-5/signalsandslots.html
Related
I am developing an QT application under QT5.13, and I am trying to connect a signal with a slot of the same class because the end goal was to connect the signal of this class with the slot of a seconde class but it doesn't work in both cases and so I tried to validate it in the same class before going to the second step.
There is my code :
udpserver.h :
#ifndef UDPSERVER_H
#define UDPSERVER_H
#include <QObject>
#include <QUdpSocket>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
class UDPServer : public QObject
{
Q_OBJECT
public:
explicit UDPServer(QObject *parent = nullptr);
QUdpSocket *getSocket() const;
void Send(QString d);
void pMsg(QByteArray App_Msg);
signals:
void ack_gui(QString ack_msg);
public slots:
void readyRead();
void ackRead(QString _ack_msg);
private:
QUdpSocket *socket;
};
#endif // UDPSERVER_H
udpserver.cpp:
#include "udpserver.h"
UDPServer::UDPServer(QObject *parent) : QObject(parent)
{
socket = new QUdpSocket(this);
QTextStream(stdout) << "Socket Server created ! " << endl;
socket->bind(QHostAddress::LocalHost, QT_SERVER_PORT);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(ack_gui(QString)), this, SLOT(ackRead(QString)));
}
QUdpSocket *UDPServer::getSocket() const
{
return socket;
}
void UDPServer::SendData(QString d)
{
keyprod prod1;
QByteArray Data;
QJsonObject Js_command = prod1.ObjectFromString(d);
Data.append(d);
socket->writeDatagram(Data, QHostAddress::LocalHost, PYTHON_SERVER_PORT);
qDebug() << "catch! " << endl;
}
void UDPServer::pMsg(QByteArray App_Msg)
{
QJsonDocument JsonDocument = QJsonDocument::fromJson(App_Msg);
QJsonObject JsonApp_Msg = JsonDocument.object();
QString Typo = JsonApp_Msg["no"].toString();
emit ack_gui(Typo);
}
void UDPServer::readyRead()
{
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(buffer.data(), buffer.size(), &sender, &senderPort);
pMsg(buffer);
}
void UDPServer::ackRead(QString _ack_msg)
{
qDebug() << "Message : " << _ack_msg;
}
As you can see it is a very classic class nothing very complicated in QT,the first connects works, but the second where I use my personal signal does not work :
connect(socket, SIGNAL(ack_gui(QString)), this, SLOT(ackRead(QString)));
The code are compiled, but when i lunch it, i got this :
QObject::connect: No such signal QUdpSocket::ack_gui(QString) in ../../udpserver.cpp
I also tried the new connect syntax in QT5 but it didn't work.
I know this topic has been touched on several times already but i have already checked these topics and still haven't found a solution can you help me please.
Thank you in advance for your help
That's because the ack_gui signal is a member of your UDPServer class not QUdpSocket.
Use the new signal/slot syntax...
connect(this, &UDPServer::ack_gui, this, &UDPServer::ackRead);
Do not use the old signal/slot connection, you will get better compile time warnings with the new one: https://wiki.qt.io/New_Signal_Slot_Syntax
You are connecting QUdpSocket to your UDPServer. Your UdpServer has ack_gui signal but QUdpSocket has not!
#include "dialog.h"
#include "ui_dialog.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QtWidgets>
#include <QString>
#include <string>
#include <QObject>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//ui->degree_lcdNumber->display("---");
// ui->distance_lcdNumber->display("---");
arduino_is_available = false;
port_name = "";
arduino =new QSerialPort;
serialBuffer = "";
foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {
if(serialPortInfo.hasVendorIdentifier() &&serialPortInfo.hasProductIdentifier()){
if(serialPortInfo.vendorIdentifier() == arduino_uno_vendorid){
if(serialPortInfo.productIdentifier()== arduino_uno_productid){
port_name = serialPortInfo.portName();
arduino_is_available = true;
}
}
}
}
if(arduino_is_available){
//open and configure the port
arduino->setPortName(port_name);
arduino->open(QSerialPort::ReadOnly);
arduino->setBaudRate(QSerialPort::Baud9600);
arduino->setDataBits(QSerialPort::Data8);
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
arduino->setFlowControl(QSerialPort::NoFlowControl);
QObject::connect(arduino,SIGNAL(readyRead()),this,SLOT(&serialReceived()));
}else{
//give error message
QMessageBox::warning(this,"Port Error","Couldn't find the Arduino!");
}
}
Dialog::~Dialog()
{
if(arduino->isOpen()){
arduino->close();
}
delete ui;
}
void Dialog::serialReceived(){
qDebug()<<"works" ;
QStringList bufferSplit = serialBuffer.split(".");
serialData = arduino->readAll();
serialBuffer += QString::fromStdString(serialData.toStdString());
serialBuffer = ",";
qDebug()<<bufferSplit;
}
void Dialog::updateLCD(const QString sensor_reading){
// ui->degree_lcdNumber->display(sensor_reading);
}
(.h)
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QSerialPort>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QSerialPort *arduino;
static const quint16 arduino_uno_vendorid =9025;
static const quint16 arduino_uno_productid =67;
void updateLCD(const QString);
void serialReceived();
QString port_name;
//void readSerial();
QByteArray serialData;
QString serialBuffer;
bool arduino_is_available;
};
#endif // DIALOG_H
I just started the Qt. I want to connect Qt with arduino serially. I am reading the data but I am not able to connect with arduino slot.
I am getting a message after compilation. The message is QObject::connect: No such slot Dialog::&serialReceived() in ..\serial_sensor\dialog.cpp:45
QObject::connect: (receiver name: 'Dialog').
Can I know why?
As per the Qt Signals and Slot documentation, the Qt signals and slots have to be declared under signals: and public slots: respectively.
Why do we do that ?
Since slots are normal member functions, they follow the normal C++ rules when called directly. However, as slots, they can be invoked by any component, regardless of its access level, via a signal-slot connection. This means that a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class.( as per Qt Documentation)
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots :
void serialReceived();
signals :
// Declare Signals here.
private:
// other private declarations.
};
The reason your connection is failing is that your connect syntax is wrong. Either you have mixed Qt's functor and string based connections or accidentally added & in front of serialReceived. Below you can find two ways to do your connection. The first one is preferred. You can read more from here. Because Dialog is QObject based class you can just call connect.
Functor based connection:
connect(arduino, &QSerialPort::readyRead, this, &Dialog::serialReceived);
String based connection:
connect(arduino, SIGNAL(readyRead()), this, SLOT(serialReceived()));
If you are using Qt4 you have to use slots in your declaration. In Qt5 slots is not strictly required for connections but it should still be used. If you don't use it you can't use introspection. You can't e.g. call QMetaObject::invokeMethod. So, in short add slots to your header file as others have already suggested.
public slots:
void serialReceived();
I'm tryng to connect() a signal in thread 2 to slot in a main thread, I have constructor like that, which runs in thread 2 as a child class of QThread:
InputHandler::InputHandler()
{
connect(this, SIGNAL(write(User*, Message)), TTCServer::ttcserver, SLOT(write(User*, Message)));
qDebug() << "new thread created!";
}
but I get an runtime error
QObject::connect: No such signal QThread::write(User*, Message)
My inputhandler.h looks like that:
#ifndef INPUTHANDLER_H
#define INPUTHANDLER_H
#include <QThread>
#include <QDebug>
#include <QString>
#include "message.h"
#include "data.h"
class InputHandler : public QThread
{
public:
InputHandler();
void run();
private:
Message message;
void login(User* user, QString login);
void sendLogins(User* user);
void startGameWith(User* user, QString opponentLogin);
signals:
void write(User* user, Message message);
};
#endif // INPUTHANDLER_H
And If it does matter, I'm also inncluding ttcserver.h:
#ifndef TTCSERVER_H
#define TTCSERVER_H
#include <QTcpServer>
#include <QObject>
#include <QDebug>
#include "data.h"
#include "user.h"
#include "message.h"
#include "inputhandler.h"
class TTCServer : public QTcpServer
{
Q_OBJECT
public:
explicit TTCServer();
static TTCServer* ttcserver;
void run();
signals:
public slots:
void newConnection();
void write(User* user, Message message);
private:
QTcpServer* server;
Message* message;
void handleInputFrom(User* user);
};
#endif
// TTCSERVER_H
void write method is definied in ttcserver.cpp like that:
void TTCServer::write(User* user, Message message)
{
qDebug() << "Signal recieved!";
}
So why write(User*, Message) in a connect() function tries to be QThread::write() instead of InputHandler::write()?
User and Message are classes, to be clear.
You forgot to add the Q_OBJECT macro into InputHandler:
class InputHandler : public QThread
{
Q_OBJECT
public:
InputHandler();
void run();
<...>
Since the macro is missing, moc will not create the corresponding code for signals/slots to work in that class, thus it tries to connect to QObject, since it does have the macro, and is the base class.
I'm new in QT5 and decided to create simple multithreaded tcp server. I've read examples provided in QT but they have additional functions and complexity which I'm trying to avoid at this point. Here is my code:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
#include <QTcpSocket>
#include "threadz.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
signals:
public slots:
void newConnection();
private:
QTcpServer *serv;
};
#endif // SERVER_H
threadz.h
#ifndef THREADZ_H
#define THREADZ_H
#include <QThread>
#include <QDebug>
#include "server.h"
class Threadz : public QThread
{
Q_OBJECT
public:
explicit Threadz(QObject *parent = 0);
void run(QTcpServer *serv);
signals:
public slots:
};
#endif // THREADZ_H
server.cpp
#include "server.h"
Server::Server(QObject *parent) :
QTcpServer(parent)
{
serv = new QTcpServer(this);
connect(serv, SIGNAL(newConnection()), this, SLOT(newConnection()));
if(!serv->listen(QHostAddress::Any, 1234))
{
qDebug() << "Error";
}
}
void Server::newConnection()
{
Threadz *thred = new Threadz();
thred->start();
}
threadz.cpp
#include "threadz.h"
Threadz::Threadz(QObject *parent) :
QThread(parent)
{
}
void Threadz::run(QTcpServer *serv)
{
QTcpSocket *socket = serv->nextPendingConnection();
socket->write("Hello!r\n");
socket->waitForBytesWritten();
socket->close();
}
main.cpp
#include <QCoreApplication>
#include "simplehttp.h"
#include "server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server gio;
return a.exec();
}
Basically, Im trying to create new thread for every client that connects server. But problem is that when I run this code and connect server with telnet 127.0.0.1 1234 nothing is printed on the screen. No errors but nothing is printed neither. Im using ubuntu 14.04. Sorry if question is silly and thanks in advance.
The QThread::run function is not implemented.
void QThread::run() [virtual protected]
The starting point for the thread. After calling start(), the newly created thread calls this function. The default implementation simply calls exec().
You can reimplement this function to facilitate advanced thread management. Returning from this method will end the execution of the thread.
Instead you implemented void Threadz::run(QTcpServer *serv) but something needs to call this function.
I have some trouble with using enum types in signals. Basicly I have two classes, a state machine and a thread handling the state machine. When the state is changed I want to send a signal with the new state. I also want to represent the state using an enum. In my full blown code the state machine is implemented in a separate shared library, but the code below gives the exact same error.
When I run the code I get the following behaviour:
kotte#EMO-Ubuntu:sigenum $ ./sigenum
Object::connect: No such slot MyThread::onNewState(state)
Test signal
Test signal
...
I have four files in my sample code: statemachine.h, statemachine.cpp, main.h and main.cpp. The main function simply starts the thread, the thread then creates an instance of the StateMachine and processes signals from the StateMachine. I am pretty new to Qt, so I was a bit puzzled when I realised that you have to enclose the enum with Q_ENUMS and register it with the type system. So It's fully possible that I've made some rookie mistake
The code below is a bit long, but I wanted it to be as similar to my real code as possible.
statemachine.h looks like:
// statemachine.h
#ifndef _STATEMACHINE_H
#define _STATEMACHINE_H
#include <QtCore>
class StateMachine : public QObject
{
Q_OBJECT
Q_ENUMS(state)
public:
enum state {S0, S1, S2};
void setState(state newState);
signals:
void stateChanged(state newState);
void testSignal(void);
};
Q_DECLARE_METATYPE(StateMachine::state);
#endif
And it is implemented as:
// statemachine.cpp
#include <QtCore>
#include "statemachine.h"
void StateMachine::setState(state newState)
{
emit stateChanged(newState);
emit testSignal();
}
The thread is defined as
// main.h
#ifndef _MAIN_H
#define _MAIN_H
#include <QtCore>
#include "statemachine.h"
class MyThread : public QThread
{
Q_OBJECT
private:
void run(void);
private slots:
void onNewState(StateMachine::state);
void onTestSignal(void);
private:
StateMachine *myStateMachine;
};
#endif
And it is implemented as follows:
// main.cpp
#include <QtCore>
#include <QApplication>
#include "statemachine.h"
#include "main.h"
void MyThread::run()
{
myStateMachine = new StateMachine();
qRegisterMetaType<StateMachine::state>("state");
// This does not work
connect(myStateMachine, SIGNAL(stateChanged(state)),
this, SLOT(onNewState(state)));
// But this does...
connect(myStateMachine, SIGNAL(testSignal()),
this, SLOT(onTestSignal()));
forever {
// ...
myStateMachine->setState(StateMachine::S0);
}
}
void MyThread::onTestSignal()
{
qDebug() << "Test signal";
}
void MyThread::onNewState(StateMachine::state newState)
{
qDebug() << "New state is:" << newState;
}
By using fully qualified names everywhere I got it to work
If I change the declaration of stateChanged() to
signals:
void stateChanged(StateMachine::state newState);
And registers the type with
qRegisterMetaType<StateMachine::state>("StateMachine::state");
and also uses this name in the connect statement
connect(myStateMachine, SIGNAL(stateChanged(StateMachine::state)),
this, SLOT(onNewState(StateMachine::state)));
Wouldn't have solved this without the input from drescherjm, thanks :-)
I believe the following is state is not defined in your MyThread class.
Use the following
connect(myStateMachine, SIGNAL(stateChanged(StateMachine::state)),
this, SLOT(onNewState(StateMachine::state)));
Edit:
Maybe this will work
connect(myStateMachine, SIGNAL(stateChanged(state)),
this, SLOT(onNewState(StateMachine::state)));
You should get rid of SIGNAL and SLOT since Qt can detect mismatches at compile time. You can also avoid having to use Q_DECLARE_METATYPE and qRegisterMetaType() by using Q_ENUM instead of Q_ENUMS - this was introduced in Qt 5.5, Finally enum class is a strongly typed version of enum:
// statemachine.h
#ifndef _STATEMACHINE_H
#define _STATEMACHINE_H
#include <QtCore>
class StateMachine : public QObject
{
Q_OBJECT
Q_ENUM(state)
public:
enum class state {S0, S1, S2};
void setState(state newState);
signals:
void stateChanged(state newState);
void testSignal(void);
};
#endif
// main.cpp
#include <QtCore>
#include <QApplication>
#include "statemachine.h"
#include "main.h"
void MyThread::run()
{
myStateMachine = new StateMachine();
connect(myStateMachine, &StateMachine::stateChanged, this, &MyThread::NewState);
connect(myStateMachine, &StateMachine::testSignal, this, &MyThread::onTestSignal);
forever {
// ...
myStateMachine->setState(StateMachine::S0);
}
}