I have a program that communicate with serial port.I dont want to use readyRead Signal I want to emit dataReceived signal when bytes come from serial, this signal connect to a slot to parse packet, but when I emit a Signal from reading Thread I have a error
the code is:
commSer.h:
#ifndef COMMSERIAL_H
#define COMMSERIAL_H
#include<QtSerialPort>
#include"fileaccess.h"
#include <QtCore/qglobal.h>
#include<QThread>
class CommSerial:public QThread
{
private:
QSerialPort *skt;
QString portName;
bool serialPortIsOepn;
FileAccess *file;
void initSkt();
void openPort();
signals:
void dataReceived(QByteArray);
public slots:
void writeToFile(QString);
void sendTo(QString);
void recievePacket(QByteArray);
public:
CommSerial();
~CommSerial();
bool stopReading;
void run(void);
QSerialPort* getPort(void);
};
#endif // COMMSERIAL_H
comSer.cpp
#include "commserial.h"
void CommSerial::initSkt()
{
skt=new QSerialPort();
portName="com3";
skt->setPortName(portName);
skt->setBaudRate(QSerialPort::Baud9600);
skt->setDataBits(QSerialPort::Data8);
skt->setParity(QSerialPort::NoParity);
skt->setStopBits(QSerialPort::OneStop);
skt->setFlowControl(QSerialPort::NoFlowControl);
connect(this,SIGNAL(dataReceived),this,SLOT(recievePacket()));
}
#include<QDebug>
void CommSerial::openPort()
{
if(skt->isOpen())
{
skt->close();
}
try {
skt->open(QIODevice::ReadWrite);
serialPortIsOepn=true;
} catch (const std::exception& ex) {
qDebug()<<"Erorr in :"<<ex.what();
serialPortIsOepn=false;
}
}
void CommSerial::writeToFile(QString str)
{
if(file->isOpen)
{
//QByteArray ba=QByteArray::fromStdString( str.toStdString());
//file->writeToFile(ba);
file->writeToFile(str);
}else {
qDebug()<<"serial port is not open";
}
}
void CommSerial::sendTo(QString str)
{
if(serialPortIsOepn)
{
QByteArray ba=QByteArray::fromStdString(str.toStdString());
skt->write(ba);
}else {
qDebug()<<"serial port is not open now";
}
}
void CommSerial::recievePacket(QByteArray ba)
{
QByteArray recBa=ba;
}
CommSerial::CommSerial()
{
stopReading=false;
serialPortIsOepn=false;
file=new FileAccess("d:/logSerial.txt");
file->openFile();
initSkt();
openPort();
}
CommSerial::~CommSerial()
{
skt->close();
file->~FileAccess();
}
void CommSerial::run()
{
while(!stopReading)
{
if(!skt->waitForReadyRead())
{
qDebug()<<"Serial Port has been closed";
stopReading=true;
break;
}
if(skt->bytesAvailable()>0)
{
QByteArray recBa=skt->readAll();
emit dataReceived(recBa); // this line has a error
}
msleep(100);
}
}
QSerialPort* CommSerial::getPort()
{
return skt;
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
skt=new CommSerial();
connect(skt->getPort(),SIGNAL(dataReceived()),this,SLOT(showRecievdData()));
}
errors:
error: undefined reference to `CommSerial::dataReceived(QByteArray)'
collect2.exe:-1: error: error: ld returned 1 exit status
The Q_OBJECT macro is missing
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.
Related
Started using QtRO and generated files inherently complain about vtable:
#ifndef REP_REMOTEEXAMPLE_H
#define REP_REMOTEEXAMPLE_H
// This is an autogenerated file.
// Do not edit this file, any changes made will be lost the next time it is generated.
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmetatype.h>
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectpendingcall.h>
#include <QtRemoteObjects/qremoteobjectreplica.h>
class remoteExampleReplica : public QRemoteObjectReplica
{
Q_OBJECT
Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "remoteExample")
Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, "5e40a606abdd95f709878d419edaa735fce25d0d")
public:
remoteExampleReplica() : QRemoteObjectReplica() { initialize(); }
static void registerMetatypes()
{
static bool initialized = false;
if (initialized)
return;
initialized = true;
}
private:
remoteExampleReplica(QRemoteObjectNode *node, const QString &name = QString())
: QRemoteObjectReplica(ConstructWithNode)
{
initializeNode(node, name);
}
void initialize() override
{
remoteExampleReplica::registerMetatypes();
QVariantList properties;
properties.reserve(0);
setProperties(properties);
}
public:
virtual ~remoteExampleReplica() {}
Q_SIGNALS:
void Close(QString a);
void Open(QString b);
public Q_SLOTS:
void onClosed()
{
static int __repc_index = remoteExampleReplica::staticMetaObject.indexOfSlot("onClosed()");
QVariantList __repc_args;
send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
}
void onOpened()
{
static int __repc_index = remoteExampleReplica::staticMetaObject.indexOfSlot("onOpened()");
QVariantList __repc_args;
send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
}
private:
friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);
};
#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
#endif
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
#endif // REP_REMOTEEXAMPLE_H
The issue points to the private constructor. I only included the replica header in my code without really using the remote object as a test run. I've read a lot about vtables how they work and when the linker complains about the vtable but in this case, with the private constructor, I'm not sure what the issue is. Am I missing an implementation of the remote object? Did I not generate the files correctly?
.rep:
class remoteExample
{
SIGNAL(Close(QString a));
SIGNAL(Open(QString b));
SLOT(onClosed());
SLOT(onOpened());
};
I have a simple project on the demo of QThread using QtCreator4.5 and Qt5.7. In the project, three pushbuttons, threadA, threadB and quit, are created. My intention is to print A and B in the console when the threadA and threadB are clicked respectively, and the application is to be quitted when 'quit' is pressed.
Here is mythread.h:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QString>
class mythread : public QThread
{
Q_OBJECT
public:
mythread();
void setMessage(const QString &message);
void stop();
protected:
void run();
private:
QString messageStr;
volatile bool stopped;
};
#endif // MYTHREAD_H
The mythread.cpp:
#include "mythread.h"
#include <iostream>
mythread::mythread()
{
stopped = false;
}
void mythread::setMessage(const QString &message)
{
messageStr = message;
}
void mythread::stop()
{
stopped = true;
}
void mythread::run()
{
while(!stopped)
std::cout<<qPrintable(messageStr);
stopped = false;
std::cout<< std::endl;
}
The mainwindow.cpp is:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_threadA_clicked()
{
mythreadA.start();
mythreadA.setMessage("A");
}
void MainWindow::on_threadB_clicked()
{
mythreadB.start();
mythreadB.setMessage("B");
}
void MainWindow::on_quit_clicked()
{
mythreadA.stop();
mythreadB.stop();
MainWindow::close();
}
When I run the project, the printed results are displayed in the Application Output of the QtCreator, not in an external prompt console. Quitting the application makes QtCreator no respond for a while, but finally restore to normal. It seems that the threads are still running when the application is quitted.
I have tested your code and there is nothing wrong with Qt Creator that is not frozen.
However, as your code is written, your threads are probably still running when you quit the application. Moreover, the private member stopped should be protected by a mutex, as volatile won't do this job.
To protect your private variable stopped with a mutex, you can use for example QMutexLocker in the following way :
void MyThread::stop() // called by the GUI Thread
{
const QMutexLocker locker(&m_mutex);
stopped = true;
}
and to read the value of the boolean :
bool MyThread::isStopped // called by run()
{
const QMutexLocker locker(&m_mutex);
return stopped;
}
Finally to ensure that the threads are properly finished when you press the quit button :
void MainWindow::on_quit_clicked()
{
mythreadA.stop();
mythreadB.stop();
myThreadA.wait();
myThreadB.wait();
this->close(); // close the main application
}
I'm working at a socket class for my application that will introduce me in QT framework. When I try to build I get this error: 'this' is unavailable for static member functions.
This is my class .h and .cpp
#pragma once
#include <QObject>
class QTcpSocket;
namespace Ps{
class InstSocket : public QObject
{
Q_OBJECT
public:
InstSocket(QObject *parent=0);
bool Connect();
bool isOpen();
void Disconnect();
//Geters
QString GetHostName() const {return m_hostName;}
quint16 GetPort() const {return m_port;}
//seters
void SetHostName(const QString& value);
void SetPort(quint16 value);
void SetLongWaitMs(int value){m_longWaitMs = value;}
void SetShortWaitMs(int value){m_shortWaitMs = value;}
void WriteData(const QString &data) const;
~InstSocket();
QString ReadData() const;
signals:
static void NotifyConnected();
static void NotifyDisconnected();
private slots:
void onConnected();
void onDisconnected();
private:
//this holds a reference to QtcpSocket
QTcpSocket& m_socket;
QString m_hostName;
quint16 m_port;
int m_shortWaitMs;
int m_longWaitMs;
explicit InstSocket(const InstSocket& rhs) = delete;
InstSocket& operator= (const InstSocket& rhs) = delete;
};
}
and the cpp:
#include "instsocket.h"
#include "QTcpSocket"
#include "QDebug"
#include "utils.h"
namespace Ps
{
InstSocket::InstSocket(QObject *parent) :
QObject(parent),
m_socket(*new QTcpSocket(this)),
m_hostName(""),
m_port(0),
m_shortWaitMs(0),
m_longWaitMs(0)
{
/* my signals are wired to the undelying socket signals, the signal connected is triggered, when a conection
* is established. This will be wired to onConnected and Disconnected slots*/
connect(&m_socket, &QTcpSocket::connected, this, &InstSocket::onConnected);
connect(&m_socket, &QTcpSocket::disconnected, this, &InstSocket::onDisconnected);
}
bool InstSocket::Connect()
{
qDebug() << "attempting to connect to "<< m_hostName << "on port" << m_port << "with wait time: "<<m_longWaitMs;
m_socket.connectToHost(m_hostName, m_port, QTcpSocket::ReadWrite);
return m_socket.waitForConnected(m_longWaitMs);
}
bool InstSocket::isOpen()
{
return m_socket.isOpen();
}
void InstSocket::Disconnect()
{
if(!isOpen()) return;
m_socket.disconnectFromHost();
}
void InstSocket::onConnected()
{
emit NotifyConnected();
}
void InstSocket::onDisconnected()
{
emit NotifyDisconnected();
}
void InstSocket::SetHostName(const QString &value)
{
m_hostName = value;
}
void InstSocket::SetPort(quint16 value)
{
m_port = value;
}
void InstSocket::WriteData(const QString &data) const
{
/*support for writeing to socket. The write metod of the socket will return the number of bites writen*/
int bytes_written = m_socket.write(qPrintable(data));
qDebug() << "Bytes written: "<<bytes_written;
}
QString InstSocket::ReadData() const
{
if(!m_socket.isReadable())
{
return "ERROR: Socket is unreadable.";
}
QString result;
//until the socket reports there is no data available
while(!m_socket.atEnd())
{
result.append(m_socket.readAll());
/*since typically a PC would be much faster at reading than an instrument might be at writing
* instrument must have a chance to queue up more data in case the message it's sending us is long.*/
m_socket.waitForReadyRead(m_shortWaitMs);
}
return result;
}
InstSocket::~InstSocket()
{
Utils::DestructorMsg(this);
}
}
and this is the error:
Qt Projects\build-Vfp-Desktop_Qt_5_7_0_MSVC2015_64bit-Debug\debug\moc_instsocket.cpp:-1: In static member function 'static void Ps::InstSocket::NotifyConnected()':
error: 'this' is unavailable for static member functions
QMetaObject::activate(this, &staticMetaObject, 0, Q_NULLPTR); In static member function 'static void Ps::InstSocket::NotifyDisconnected()':
error: 'this' is unavailable for static member functions
QMetaObject::activate(this, &staticMetaObject, 1, Q_NULLPTR);
When I clicked on them, QT creator took me to moc_instsocket.cpp (that is in build folder and poit to this:
// SIGNAL 0
void Ps::InstSocket::NotifyConnected()
{
QMetaObject::activate(this, &staticMetaObject, 0, Q_NULLPTR);
}
// SIGNAL 1
void Ps::InstSocket::NotifyDisconnected()
{
QMetaObject::activate(this, &staticMetaObject, 1, Q_NULLPTR);
}
I can't figure out what to do althought I checked all the code several times. There is no need to know about utils class since there are just some debug messages. Did anyone know how to fix it?
What is the meaning of static signal? In Qt signals and slots are used on object level.
signals:
static void NotifyConnected();
static void NotifyDisconnected();
All classes that inherit from QObject or one of its subclasses (e.g., QWidget) can contain signals and slots. Signals are emitted by objects when they change their state in a way that may be interesting to other objects. This is all the object does to communicate. It does not know or care whether anything is receiving the signals it emits. This is true information encapsulation, and ensures that the object can be used as a software component. Signal Slots documentation
i am writing client server application using gsoap lib. the problem is that a have a heavy process function in my server.i want to when special client call this function, the server send message for this special client that "your answer is ready" when this client answer is ready. and its possible that multiple client call this function in same time.
is there any tool like asynchronAnswer in qt? and if not how can i handle it with qt or gsoap tools?
whats the true architect of handle this problems? using multi thread in client calling and wait for response in other thread or exactly call client by its ip in server or something better?
thanks,
You can try to use QWebSocket for this task. You have connected client list, if client send a request for "heavy process function", you are puting in thread pool, and sending replay to the specific client after calculations are done. In code it will be something like this:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QtWebSockets>
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
~Server();
signals:
void closed();
public slots:
private slots:
void onNewConnection();
void onMessage(QString message);
void onDisconnected();
private:
QWebSocketServer* m_pWebSocketServer;
QList<QWebSocket*> m_clients;
};
#endif // SERVER_H
server.cpp
#include <QThreadPool>
#include "server.h"
#include "heavytask.h"
Server::Server(QObject *parent) :
QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Server"), QWebSocketServer::NonSecureMode, this))
{
if (m_pWebSocketServer->listen(QHostAddress::Any, 4000)) {
connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &Server::onNewConnection);
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &Server::closed);
}
}
void Server::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::textMessageReceived, this, &Server::onMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Server::onDisconnected);
m_clients << pSocket;
}
void Server::onMessage(QString message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (message == "Start heavy process function in your server, please") {
HeavyTask* ht = new HeavyTask(pClient);
QThreadPool::globalInstance()->start(ht);
}
}
void Server::onDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient) {
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Server::~Server()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
heavytask.h
#ifndef HEAVYTASK_H
#define HEAVYTASK_H
#include <QThreadPool>
#include <QRunnable>
#include <QWebSocket>
class HeavyTask : public QRunnable
{
public:
explicit HeavyTask(QWebSocket* client);
void run();
private:
QWebSocket* m_client;
};
#endif // HEAVYTASK_H
heavytask.cpp
#include "heavytask.h"
HeavyTask::HeavyTask(QWebSocket* client) : m_client(client)
{
}
void HeavyTask::run()
{
/*
Do your havy task;
*/
if (m_client != nullptr) {
if (m_client->isValid()) {
m_client->sendTextMessage("Your answer is ready!");
}
}
}
and main.cpp
#include <QCoreApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server(&a);
QObject::connect(&server, &Server::closed, &a, &QCoreApplication::quit);
return a.exec();
}
Hope it'll be useful. (Not tasted at all, but compiling)
I have something like that:
Prueba.h
#include <QObject>
class Prueba:public QObject
{
Q_OBJECT
private:
bool waiting;
public:
Prueba();
void test();
void fin();
signals:
void comenzo();
};
Prueba.cpp
#include "prueba.h"
#include <QDebug>
Prueba::Prueba()
{
waiting=true;
}
void Prueba::test()
{
qDebug()<<"Comenzando";
emit(comenzo());
while(waiting) {
qDebug()<<"Esperando";
}
qDebug()<<"Termino";
}
void Prueba::fin()
{
waiting=false;
}
Principal.h
#include <QObject>
#include "prueba.h"
class Principal:public QObject
{
Q_OBJECT
private:
Prueba * prueba;
public:
Principal();
private slots:
void processSignal();
};
Principal.cpp
#include <QDebug>
Principal::Principal()
{
prueba=new Prueba();
connect(prueba,SIGNAL(comenzo()),SLOT(processSignal()));
prueba->test();
}
void Principal::processSignal()
{
for(int i=0;i<1000;i++) {
qDebug()<<"Algo";
}
prueba->fin();
}
When I call prueba->test(), and it emit the signal "comenzo", Principal::proccessSignal is completely executed, and never enters to the cycle "while(waiting)". What I need to do for that the code inside the loop is executed?
My guess is your signal connection. By default Qt will execute your signal as a direct call to the slot the objects are in the same thread as you can see here:
QMetaObject::Connection QObject::connect(
const QObject * sender, const char * signal,
const char * method, Qt::ConnectionType type = Qt::AutoConnection) const
See Qt::ConnectionType here http://qt-project.org/doc/qt-5.0/qtcore/qt.html#ConnectionType-enum
So if you use
Qt::QueuedConnection
in your signal connection
connect(prueba,SIGNAL(comenzo()),SLOT(processSignal()), Qt::QueuedConnection);
It should work as expected. See
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.