Pass signals and data from a class to another on Qt - c++

I will post the code first as it will be easier to understand after that.
Basically, I have a default class, MainWindow:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include "tcpsocket.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
//This is my class
tcpsocket *socket;
public slots:
void updateUI(QString);
private slots:
void on_connectButton_clicked();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#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::updateUI(QString msg)
{
qDebug() << "GOOD, SLOT ACCESSED FROM ANOTHER CLASS";
ui->responseBox->setText(msg);
}
void MainWindow::on_connectButton_clicked()
{
socket = new tcpsocket();
socket->doConnect();
}
Behind is a simple form with a pushButton and a textBox.
And the second class:
tcpsocket.h
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include <QMainWindow>
#include <QObject>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QBitArray>
#include <QDebug>
#include "mainwindow.h"
class tcpsocket : public QMainWindow
{
Q_OBJECT
public:
explicit tcpsocket(QWidget *parent = 0);
void doConnect();
signals:
public slots:
void connected();
void disconnected();
void bytesWritten(qint64 bytes);
void readyRead();
private:
QTcpSocket *socket;
};
#endif // TCPSOCKET_H
and tcpsocket.cpp
#include "tcpsocket.h"
tcpsocket::tcpsocket(QWidget *parent) : QMainWindow(parent)
{
}
void tcpsocket::doConnect()
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()),this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this, SLOT(disconnected()));
connect(socket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64)));
connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
//And here I want to add a signal to a slor from main window.
//Something like this:
// connect(socket, SIGNAL(readyRead()), MainWindow, SLOT(updateUI());
qDebug() << "connecting...";
// this is not blocking call
socket->connectToHost("google.com", 80);
// we need to wait...
if(!socket->waitForConnected(5000))
{
qDebug() << "Error: " << socket->errorString();
}
}
void tcpsocket::connected()
{
qDebug() << "connected...";
// Hey server, tell me about you.
socket->write("HEAD / HTTP/1.0\r\n\r\n\r\n\r\n");
}
void tcpsocket::disconnected()
{
qDebug() << "disconnected...";
}
void tcpsocket::bytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void tcpsocket::readyRead()
{
qDebug() << "reading response...";
QString data = socket->readAll();
qDebug() << data;
//Here, I want to pass somehow this content to function updateUI, from MainWindow
// MainWindow::updateUI( data );
}
Bsically, I want to pass some data from class tcpsocket to class MainWindow
main.cpp is default code. I think it is not relevant.
To be more specific, I want that a signal from tcpsocket class to trigger a slot from MainWindow class:
void tcpsocket::doConnect()
{
socket = new QTcpSocket(this);
//local slots
connect(socket, SIGNAL(connected()),this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this, SLOT(disconnected()));
connect(socket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64)));
connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
//And here I want to add a signal to a slot from main window.
//Something like this:
// connect(socket, SIGNAL(readyRead()), MainWindow, SLOT(updateUI());
....
And the second question is how to pass some data from tcpsocket class to MainWindow class:
void tcpsocket::readyRead()
{
qDebug() << "reading response...";
QString data = socket->readAll();
qDebug() << data;
//Here, I want to pass somehow this content to function updateUI, from MainWindow
// MainWindow::updateUI( data );
}
The application run perfectly and content is fetched. But I can view the fetched content only using qDebug(); so I want to pass response to GUI, into a textBox.

Related

I have created a TCPSocket in QT, but how do i implement received data from QTCPSocket?

As the title says, i have created a client which receives data from my server. So far i can print it in my console, but i would like to work with it. (The data that the client recevies is from my Smartphones accelerometer sensor)
My Socket.h class:
#ifndef SOCKETTEST_H
#define SOCKETTEST_H
#include <QObject>
#include <QDebug>
#include <QTcpSocket>
#include <QAbstractSocket>
class SocketTest : public QObject
{
Q_OBJECT
public:
explicit SocketTest(QObject *parent = nullptr);
void Test();
signals:
public slots:
void connected();
void disconnected();
void bytesWritten( qint64 bytes);
void readyRead();
private:
QTcpSocket *socket;
};
#endif // SOCKETTEST_H
and socket.cpp :
#include "sockettest.h"
SocketTest::SocketTest(QObject *parent)
: QObject{parent}
{
}
void SocketTest::Test()
{
socket = new QTcpSocket(this);
connect (socket, SIGNAL(connected()),this, SLOT(connected()));
connect (socket, SIGNAL(disconnected()),this, SLOT(disconnected()));
connect (socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
connect (socket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64)));
qDebug() <<"Connecting...";
socket->connectToHost("MY IP", PORT);
if(!socket->waitForConnected(2000))
{
qDebug() <<"Error" << socket->errorString();
}
}
void SocketTest::connected()
{
qDebug() <<"Connected!";
socket->write("\r\n\r\n\r\n\r\n");
}
void SocketTest::disconnected()
{
qDebug() <<"Disconnected!";
}
void SocketTest::bytesWritten(qint64 bytes)
{
qDebug() <<"We wrote: " <<bytes;
}
void SocketTest::readyRead()
{
qDebug() << socket->readAll();
}
typically what i want to create, in another class, is an if statment which moves an Object based on the sent data :
if( received_data == 5 ){
this->setX(this->x()+1);
}

How to get a variable from a thread?

I have a class that creates a server with multithreading. With the help of multithreading, I can connect several users at the same time. In one stream, the QByteArray Data is written, but I need this variable in the lane or in the lane heder, so that I can output this line (i.e., QByteArray Data). How I can tranfer var Data in my main function or header main?
I want write Data in QLable or somthing...
main.c
#include "groundstation.h"
#include <QApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GroundStation w;
Server wServer;
wServer.StartServer();
//qDebug() << ServerThread::getString();
// QLabel *label = new QLabel();
//label->setText((QString));
w.show();
return a.exec();
}
server.cpp
#include "server.h"
Server::Server(QObject *parent) :
QTcpServer (parent)
{
}
void Server::StartServer(){
if(!this->listen(QHostAddress::Any, 1234)){
qDebug() << "Could not start server";
}
else {
qDebug() << "Listening...";
}
}
void Server::incomingConnection(int socketDescriptor){
qDebug() << socketDescriptor << "Connecting...";
ServerThread *thread = new ServerThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
sever.h
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
#include <QDebug>
#include "serverthread.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
void StartServer();
signals:
public slots:
protected:
void incomingConnection(int socketDescriptor);
};
#endif // SERVER_H
serverthread.cpp
#include "serverthread.h"
ServerThread::ServerThread(int id, QObject *parent) :
QThread (parent)
{
this->socketDescriptor = id;
}
void ServerThread::run(){
//thread starts here
qDebug() << socketDescriptor << " Starting thread";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor)){
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
qDebug() << socketDescriptor << " Client connected";
//make this thread a loop
exec();
}
void ServerThread::readyRead(){
Data = socket->readAll();
qDebug() << socketDescriptor << " Data in: " << Data;
socket->write(Data);
}
void ServerThread::disconnected(){
qDebug() << socketDescriptor << " Disconnected";
socket->deleteLater();
exit(0);
}
serverthread.h
#ifndef SERVERTHREAD_H
#define SERVERTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QDebug>
class ServerThread : public QThread
{
Q_OBJECT
public:
QByteArray Data;
explicit ServerThread(int id, QObject *parent = 0);
void run();
signals:
void error(QTcpSocket::SocketError socketerror);
public slots:
void readyRead();
void disconnected();
public slots:
private:
QTcpSocket *socket;
int socketDescriptor;
};
#endif // SERVERTHREAD_H

Qt execute multiple get with QNetworkAccessManager

I have to execute a lot of get requests and they have to be hadled in different ways. So far, I have this simply approach that works:
And here's the code for .h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void finish(QNetworkReply *reply);
void finish2(QNetworkReply *reply);
private:
Ui::MainWindow *ui;
QNetworkAccessManager* manager;
};
#endif // MAINWINDOW_H
And code for .cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
//First request here...
void MainWindow::on_pushButton_clicked()
{
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &MainWindow::finish);
manager->get(QNetworkRequest{QUrl{"http://www.link.com/path/"}});
}
//... is completed here
void MainWindow::finish(QNetworkReply *reply) {
if (reply->error()) {
ui->lineEdit->setText("error");
qDebug() << reply->errorString();
} else {
ui->lineEdit->setText(QString{reply->readAll()});
}
}
//Second request here...
void MainWindow::on_pushButton_2_clicked()
{
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &MainWindow::finish2);
manager->get(QNetworkRequest{QUrl{"https://ergast.com/api/f1/2008/5.json"}});
qDebug() << "chiamata";
}
//... is completed here
void MainWindow::finish2(QNetworkReply *reply) {
if (reply->error()) {
ui->lineEdit_2->setText("error");
qDebug() << reply->errorString();
} else {
ui->lineEdit_2->setText(QString{reply->readAll()});
}
}
When I press both buttons the requests happen but my UI blocks. I have tried this approach because I have seen in many examples that it's good to have a QNetworkAccessManager* manager; as private field and re-use it.
It does not seem by the way the best approach. Is there a proper way to do multiple calls?
Should I declare maybe an array of QNetworkAccessManager* and execute there all the calls?
I have also seen that there's the possibility to create a private field called QNetworkReply* reply; and then use it like this:
manager = new QNetworkAccessManager(this);
reply = manager->get(QNetworkRequest{QUrl{"http://www.link.com/path/"}});
connect(manager, &QNetworkReply::finished, this, &MainWindow::finish);
I think that this is equivalent to the method I am using but in this case I don't know how to handle multiple requests because I am bind to the finish method and I should implement all the logic there.
I have tested your code and I have not noticed that the GUI is blocked, in addition to using signals and slots you should not have that problem. However I see that you are creating dynamic memory unnecessarily, in the following code I connect the QNetworkReply to a slot, filter through the QUrl and delete the QNetworkReply:
*.h
...
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void onReplyfinished();
private:
Ui::MainWindow *ui;
QNetworkAccessManager *manager;
...
*.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
manager = new QNetworkAccessManager(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QNetworkReply *reply = manager->get(QNetworkRequest{QUrl{"http://www.link.com/path/"}});
connect(reply, &QNetworkReply::finished, this, &MainWindow::onReplyfinished);
}
void MainWindow::on_pushButton_2_clicked()
{
QNetworkReply *reply = manager->get(QNetworkRequest{QUrl{"https://ergast.com/api/f1/2008/5.json"}});
connect(reply, &QNetworkReply::finished, this, &MainWindow::onReplyfinished);
}
void MainWindow::onReplyfinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if(reply->url() == QUrl{"http://www.link.com/path/"}){
ui->lineEdit->setText(reply->error() ? "error": reply->readAll());
}
else if (reply->url() == QUrl{"https://ergast.com/api/f1/2008/5.json"}){
ui->lineEdit_2->setText(reply->error() ? "error": reply->readAll());
}
reply->deleteLater();
}

Redirecting std::cout from DLL in a separate thread to QTextEdit

The goal is to display all the application output shown in QtCreator to a QTextEdit as a debug console window so with the same application only those who have password are allowed to see the console window while normal users cannot. There is an exe with several dlls. All std::cout from DLLs and qDebug are needed to be shown in the debug console window.
To achieve this, I have followed
http://www.qtforum.org/article/39768/redirecting-std-cout-std-cerf-qdebug-to-qtextedit.html
The code works great for single thread but is hanged when a thread is started to call functions in DLL. I would like to know how to fix the problem.
code
In mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QObject>
#include <QThread>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_qd = new Q_DebugStream(std::cout,ui->textEdit); //Redirect Console output to QTextEdit
m_qd->Q_DebugStream::registerQDebugMessageHandler(); //Redirect qDebug() output to QTextEdit
connect(ui->pushButtonSingleThreadTest, SIGNAL(clicked()),this,SLOT(SingleThreadTest()));
connect(ui->pushButtonMultiThreadTest, SIGNAL(clicked()),this,SLOT(MultiThreadTest()));
}
void MainWindow::SingleThreadTest()
{
run();
}
void MainWindow::MultiThreadTest()
{
QThread *workerThread= new QThread;
ThreadWorker *worker = new ThreadWorker();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
In mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "q_debugstream.h"
#include "../ToyProj1/Header.h"
namespace Ui {
class MainWindow;
}
class ThreadWorker : public QObject
{
Q_OBJECT
public:
ThreadWorker()
{
}
private:
signals:
void finished();
public slots:
void doWork()
{
run();
emit finished();
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void SingleThreadTest();
void MultiThreadTest();
private:
Ui::MainWindow *ui;
Q_DebugStream* m_qd;
};
#endif // MAINWINDOW_H
in q_debugstream.h
#ifndef Q_DEBUGSTREAM_H
#define Q_DEBUGSTREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include "QTextEdit.h"
class Q_DebugStream : public std::basic_streambuf<char>
{
public:
Q_DebugStream(std::ostream &stream, QTextEdit* text_edit) : m_stream(stream)
{
log_window = text_edit;
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
}
~Q_DebugStream()
{
m_stream.rdbuf(m_old_buf);
}
static void registerQDebugMessageHandler(){
qInstallMessageHandler(myQDebugMessageHandler);
}
private:
static void myQDebugMessageHandler(QtMsgType, const QMessageLogContext &, const QString &msg)
{
std::cout << msg.toStdString().c_str();
}
protected:
//This is called when a std::endl has been inserted into the stream
virtual int_type overflow(int_type v)
{
if (v == '\n')
{
log_window->append("");
}
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n)
{
QString str(p);
if(str.contains("\n")){
QStringList strSplitted = str.split("\n");
log_window->moveCursor (QTextCursor::End);
log_window->insertPlainText (strSplitted.at(0)); //Index 0 is still on the same old line
for(int i = 1; i < strSplitted.size(); i++){
log_window->append(strSplitted.at(i));
}
}else{
log_window->moveCursor (QTextCursor::End);
log_window->insertPlainText (str);
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
QTextEdit* log_window;
};
#endif // Q_DEBUGSTREAM_H
In DLL,
int run()
{
std::cout << "Hello World" << std::endl;
return 0;
}
The code sample is uploaded to github for reference. Build ToyProj1 and ToyProj1GUI when repeat the problem.
https://github.com/kuwt/ToyProject.git
With the help comments in question, this solution works well with signal and slot mechanism. std::cout and qDebug are redirected to QTextEdit.
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
// Setup QMessageCatch
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
qInstallMessageHandler(MainWindow::QMessageOutput);
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QTextEdit>
#include "q_debugstream.h"
namespace Ui {
class MainWindow;
}
class ThreadWorker : public QObject
{
Q_OBJECT
public:
ThreadWorker()
{
}
private:
signals:
void finished();
public slots:
void doWork()
{
std::cout<< "Hello World2" <<std::endl;
qDebug() << "Hello World2q" ;
emit finished();
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
// QMessage
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
static void QMessageOutput(QtMsgType , const QMessageLogContext &, const QString &msg);
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
public slots:
void SingleThreadTest();
void MultiThreadTest();
private:
Ui::MainWindow *ui;
// MessageHandler for display and ThreadLogStream for redirecting cout
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
MessageHandler *msgHandler = Q_NULLPTR;
ThreadLogStream* m_qd;
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QObject>
#include <QThread>
// Catch QMessage, redirect to cout
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
void MainWindow::QMessageOutput(QtMsgType , const QMessageLogContext &, const QString &msg)
{
std::cout<<msg.toStdString().c_str()<<std::endl;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Set up ThreadLogStream, which redirect cout to signal sendLogString
// Set up MessageHandler, wgucg catch message from sendLogString and Display
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
m_qd = new ThreadLogStream(std::cout); //Redirect Console output to QTextEdit
this->msgHandler = new MessageHandler(this->ui->textEdit, this);
connect(m_qd, &ThreadLogStream::sendLogString, msgHandler, &MessageHandler::catchMessage);
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
connect(ui->pushButtonSingleThreadTest, SIGNAL(clicked()),this,SLOT(SingleThreadTest()));
connect(ui->pushButtonMultiThreadTest, SIGNAL(clicked()),this,SLOT(MultiThreadTest()));
}
void MainWindow::SingleThreadTest()
{
std::cout<< "Hello World1" <<std::endl;
qDebug() << "Hello World1q" ;
}
void MainWindow::MultiThreadTest()
{
QThread *workerThread= new QThread;
ThreadWorker *worker = new ThreadWorker();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
q_debugstream.h
#ifndef ThreadLogStream_H
#define ThreadLogStream_H
#include <iostream>
#include <streambuf>
#include <string>
#include <QScrollBar>
#include "QTextEdit"
#include "QDateTime"
// MessageHandler
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
class MessageHandler : public QObject
{
Q_OBJECT
public :
MessageHandler(QTextEdit *textEdit, QObject * parent = Q_NULLPTR) : QObject(parent), m_textEdit(textEdit){}
public slots:
void catchMessage(QString msg)
{
this->m_textEdit->append(msg);
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
private:
QTextEdit * m_textEdit;
};
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
class ThreadLogStream : public QObject, public std::basic_streambuf<char>
{
Q_OBJECT
public:
ThreadLogStream(std::ostream &stream, QObject * parent = Q_NULLPTR) :QObject(parent), m_stream(stream)
{
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
}
~ThreadLogStream()
{
// output anything that is left
if (!m_string.empty())
{
emit sendLogString(QString::fromStdString(m_string));
}
m_stream.rdbuf(m_old_buf);
}
protected:
virtual int_type overflow(int_type v)
{
if (v == '\n')
{
emit sendLogString(QString::fromStdString(m_string));
m_string.erase(m_string.begin(), m_string.end());
}
else
m_string += v;
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n)
{
m_string.append(p, p + n);
long pos = 0;
while (pos != static_cast<long>(std::string::npos))
{
pos = static_cast<long>(m_string.find('\n'));
if (pos != static_cast<long>(std::string::npos))
{
std::string tmp(m_string.begin(), m_string.begin() + pos);
emit sendLogString(QString::fromStdString(tmp));
m_string.erase(m_string.begin(), m_string.begin() + pos + 1);
}
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
std::string m_string;
signals:
void sendLogString(const QString& str);
};
#endif // ThreadLogStream_H
for long transactions, you can add:
QCoreApplication::processEvents();
in the catchMessage(QString(msg) method of the class MessageHandler in q_debugstream.h, after the append() call.
This updates textEdit 'as soon as possible'.

how to send an audio stream via tcp in a thread in Qt?

I'm trying to send an audio stream from a microphone via TCP in a thread other than the main thread. Therefore I've set up a server an I'm listening for incoming connections. Once a client connects, I want to send it the audio stream. I've read the Qt Documentation about QTcpServer, Multithreading, and QtMultimedia. I've also looked at this website for example code about multithreading and TCP servers in Qt. The problem is this message that I get during runtime:
QObject: Cannot create children for a parent that is in a different thread. (Parent is QNativeSocketEngine(0xae802a78), parent's thread is MyThread1(0x1856d28), current thread is QThread(0x1838aa0)
this is my code:
in file myserver.h
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QtNetwork>
#include <QTcpServer>
#include <mythread.h>
#include <QtMultimediaKit/QAudioFormat>
#include <QtMultimediaKit/QAudioInput>
#include <QtMultimediaKit/QAudioDeviceInfo>
class MyServer : public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(QObject *parent = 0);
void startServer();
signals:
public slots:
protected:
void incomingConnection(int socketDescriptor);
private:
QAudioInput *audioInput;
};
#endif // MYSERVER_H
in file myserver.cpp
#include "myserver.h"
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
}
void MyServer::startServer()
{
int port = 12345;
QString ipAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
for (int i = 0; i < ipAddressesList.size(); ++i)
{
if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address())
{
ipAddress = ipAddressesList.at(i).toString();
break;
}
}
if(!this->listen( QHostAddress(ipAddress),port ) )
{
qDebug() << "Could not start server";
}
else
{
qDebug() << "The server is running on\n\nIP: "<< ipAddress;
qDebug() << "\nport: " << this->serverPort() << "\n\n";
}
}
void MyServer::incomingConnection(int socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting...";
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!info.isFormatSupported(format))
{
qWarning()<<"default format not supported try to use nearest";
format = info.nearestFormat(format);
}
audioInput = new QAudioInput(format, this);
MyThread1 *thread = new MyThread1(socketDescriptor,audioInput, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
in file mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QDebug>
#include <QtMultimediaKit/QAudioInput>
class MyThread1 : public QThread
{
Q_OBJECT
public:
explicit MyThread1( int ID, QAudioInput *spk, QObject *parent = 0);
void run();
signals:
void error(QTcpSocket::SocketError socketerror);
public slots:
void sendData();
void disconnected();
private:
QTcpSocket *socket;
int socketDescriptor;
QAudioInput *speaker;
};
#endif // MYTHREAD_H
in file mythread.cpp
#include "mythread.h"
MyThread1::MyThread1( int ID, QAudioInput *spk, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
this->speaker = spk;
}
void MyThread1::run()
{
qDebug() << " Thread started";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor))
{
emit error(socket->error());
return;
}
connect( speaker->start(), SIGNAL( readyRead() ), this, SLOT( sendData() ) , Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
qDebug() << socketDescriptor << " Microphone connected";
exec();
}
void MyThread1::sendData()
{
QByteArray Data = speaker->start()->readAll();
QDataStream l_vStream(&Data, QIODevice::WriteOnly);
l_vStream.setByteOrder(QDataStream::LittleEndian);
socket->write(Data, Data.length());
socket->waitForBytesWritten();
}
void MyThread1::disconnected( )
{
qDebug() << socketDescriptor << "Mic Disconnected";
speaker->stop();
delete speaker;
socket->deleteLater();
exit(0);
}
in file main.cpp
#include <QCoreApplication>
#include <myserver.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyServer server;
server.startServer();
return a.exec();
}
Any help would really be appreciated. Thanks.