I use QTcpSocket to open a connection and receive the data. But I'm having issues reading data from then socket.
// header file
class PeerWireClient : public QTcpSocket
{
Q_OBJECT
public:
PeerWireClient(QObject *parent = 0);
private slots:
void readFromSocket();
private:
qint64 socketBytesAvailable() const { return QTcpSocket::bytesAvailable(); }
// Data waiting to be read/written
QByteArray incomingBuf;
QByteArray outgoingBuf;
};
// cpp file
PeerWireClient::PeerWireClient(QObject *parent) :
QTcpSocket(parent)
{
connect(this, SIGNAL(readyRead()), this, SLOT(readFromSocket()));
}
void PeerWireClient::readFromSocket(void)
{
qint64 oldsize, size;
qint64 readbytes = 0;
oldsize = incomingBuf.size();
size = socketBytesAvailable();
if (size > 0) {
incomingBuf.resize(oldsize + size);
readbytes = read((incomingBuf.data()+oldsize), size);
qDebug("%ld", readbytes); //
qDebug("data: %s", incomingBuf.constData());
}
}
If I try to send 281 bytes data from the other side then
the read function return 281 bytes but the is no data in buffer.
Debug:
281
data:
I dont know what I am doing wrong. How can I make this work?
Related
I want to received image through using TCP socket and display in QMl window.
currently :I am able to receive .png image from socket. and : able to display the image from local disk in qml using image provider. but while integrating the both things i am facing the issue. how to call the socket's function.
tcpserver.h
class MyTcpServer : public QObject
{
Q_OBJECT
public:
explicit MyTcpServer(QObject *parent = 0);
signals:
public slots:
void newConnection();
void on_readyRead();
private:
QTcpServer *server;
};```
```
tcpserver.cpp
QByteArray array,array1;
MyTcpServer::MyTcpServer(QObject *parent) :
QObject(parent)
{server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()),
this, SLOT(newConnection()));
connect(server,SIGNAL(readyRead()),this,SLOT(readyRead()));
if(!server->listen(QHostAddress::Any, 9999))
{
qDebug() << "Server could not start";
}
else
{
qDebug() << "Server started!";
}
}
void MyTcpServer::newConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
if(socket)
{
connect(socket ,SIGNAL(readyRead()),this,SLOT(on_readyRead()));
socket->write("Hello client \r\n");
socket->flush();
socket->waitForBytesWritten(3000);
}
}
void MyTcpServer::on_readyRead()
{
QTcpSocket * server = dynamic_cast<QTcpSocket*>(sender());
qDebug()<<"reading..";
if(server)
{
qDebug()<<"Array size " << array.size() ;
array.append(server->readAll());
if(array.size()<230400)
{
qDebug()<<"Array size " << array.size() ;
}
else {
qDebug()<<"Array size else " << array.size() ;
cv::Mat img,img1;
cv::Size const frame_size(240,320);
img = cv::Mat(240,320, CV_8UC3,array.data());
qDebug()<<"Image type " <<img.type();
qDebug()<<"Array size " << array.size() ;
qDebug()<<"beforeImage size size " << img.dims;
cv::imshow("image display",img);
cv::waitKey(5000);
QImage imdisplay((uchar*)img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
}
}
}
//socket->close()
}
```
imageprovider.cpp
QImage QmlImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
printf("In request function ..\n");
MyTcpServer *m = new MyTcpServer();
m->newConnection();
printf("after connectrion....");
QImage image1= m->on_readyRead();
printf("after request....");
return image;
}
```
You should move MyTcpServer *m = new MyTcpServer(); to ImageProvider class constructor and m to class members, also create a signal in your MyTcpServer class and connect it to your ImageProvider updateImage slot.
P.S Maybe need to change updateImage from simple function to slot.
tcpserver.h
class MyTcpServer : public QObject
{
Q_OBJECT
public:
explicit MyTcpServer(QObject *parent = 0);
signals:
void newImageReceived(QImage);
.
.
.
tcpserver.cpp on_readyRead()
cv::imshow("image display",img);
cv::waitKey(5000);
QImage imdisplay((uchar*)img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
emit newImageReceived(imdisplay);
qmlimageprovider.cpp
QmlImageProvider::QmlImageProvider()
: QQuickImageProvider(QQuickImageProvider::Image)
{
m = new MyTcpServer();
connect(m, &MyTcpServer::newImageReceived, this, &QmlImageProvider::updateImage);
m->newConnection();
}
qmlimageprovider.h
class QmlImageProvider : public QQuickImageProvider
{
public:
QmlImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
public slots:
void updateImage(QImage new_image);
private:
QImage image;
MyTcpServer *m;
};
I am writing a WebSocket client application, based on the example, where the client application needs to pass the WebSocket Protocol while establishing connection with the server. Since QtWebSockets does not support the Websocket protocols, I am writing a C++ wrapper to use libWebSockets library and emit
connected, disconnected, textReceived kind of signals similar to QWebSocket.
My client application is able to connect to the server and is receiving the text message from the server, and I have copied minimum example code below, here I am facing an issue that when I emit a signal from the callback function the signal is not actually published and the slot I have connected to this signal never executed. I have verified that the object address passed in the session data is correct (copied the Logs of my program). What am I doing wrong here.
WebSocket.h
class WebSocket : public QObject
{
Q_OBJECT
public:
WebSocket(QObject *parent = Q_NULLPTR);
~WebSocket();
signals:
void connected();
void disconnected();
void textMessageReceived(const QString &message);
private:
static int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
struct lws_context *context;
struct lws *client_wsi;
static const struct lws_protocols protocols[];
};
WebSocket.cpp
const struct lws_protocols WebSocket::protocols[] = {
{
"dumb_protocol",
callback_dumb_increment,
sizeof(per_session_data),
0,
},
{ NULL, NULL, 0, 0 }
};
WebSocket::WebSocket(QObject *parent) : QObject(parent)
{
struct lws_context_creation_info info;
struct lws_client_connect_info i;
int n = 0;
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
qDebug() << "[parent] address: " << this;
info.user = this;
/*
* since we know this lws context is only ever going to be used with
* one client wsis / fds / sockets at a time, let lws know it doesn't
* have to use the default allocations for fd tables up to ulimit -n.
* It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
* will use.
*/
info.fd_limit_per_thread = 1 + 1 + 1;
context = lws_create_context(&info);
if (!context) {
qDebug() << "lws init failed";
}
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
i.context = context;
i.port = 7070;
i.address = "localhost";
i.path = "/";
i.host = i.address;
i.origin = i.address;
i.pwsi = &client_wsi;
lws_client_connect_via_info(&i);
while (n >= 0 && client_wsi)
n = lws_service(context, 0);
}
int WebSocket::callback_dumb_increment( struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len )
{
/* This will be same for every connected peer */
void *userdata = lws_context_user(lws_get_context(wsi));
qDebug() << "userData address: " << userdata;
QString message = "";
switch (reason) {
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
if (in)
qDebug() << "CLIENT_CONNECTION_ERROR: " << (char *)in;
else
qDebug() << "CLIENT_CONNECTION_ERROR: (null)";
wsi = NULL;
break;
case LWS_CALLBACK_CLIENT_ESTABLISHED:
qDebug() << __func__ << " established";
emit static_cast<WebSocket*>(userdata)->connected();
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
message = QString::fromUtf8((const char *)in);
qDebug() << "RX: " << message;
emit static_cast<WebSocket*>(userdata)->textMessageReceived(message);
break;
case LWS_CALLBACK_CLIENT_CLOSED:
wsi = NULL;
emit static_cast<WebSocket*>(userdata)->disconnected();
break;
default:
break;
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
}
SocketClient.h
class SocketClient : public QObject
{
Q_OBJECT
public:
explicit SocketClient(QObject *parent = Q_NULLPTR);
~SocketClient();
public slots:
void onConnected();
void onTextMessageReceived(QString message);
private:
std::shared_ptr<WebSocket> webSock = nullptr;
};
SocketClient.cpp
SocketClient::SocketClient(QObject *parent) :QObject(parent)
{
webSock = std::make_shared<WebSocket>(this);
connect(webSock .get(), &WebSocket::connected, this, &SocketClient::onConnected);
connect(webSock .get(), &WebSocket::textMessageReceived,
this, &SocketClient::onTextMessageReceived);
}
Logs:
[parent] address: WebSocket(0x1b2cae32140)
userData address: 0x1b2cae32140
WebSocket::callback_dumb_increment established
userData address: 0x1b2cae32140
RX: "Hello World"
I am trying to implement my own wrapper over QUdpSocket because of it is uncomfortable to use. I can use it, but anyway I need to implement some intermediate buffer for access to QDataStream operations. In additional:
I sublass QIODevice,
header (bit simplified):
class BerUdp : public QIODevice
{
Q_OBJECT
void startup();
public:
void setHostToWrite(const QHostAddress &address, quint16 port);
void setPortToRead(quint16 port);
qint64 bytesAvailable() const;
protected: // Reimplement:
qint64 readData(char *data, qint64 maxSize);
qint64 writeData(const char *data, qint64 maxSize);
private:
QUdpSocket* dev_write; // udp socket to write
QUdpSocket* dev_read; // udp socket to read
QBuffer m_buffer; // buffer to store received datagrams
};
.cpp file:
void BerUdp::startup()
{
m_buffer.open(QIODevice::ReadWrite);
open(QIODevice::ReadWrite);
}
void BerUdp::setHostToWrite(const QHostAddress &address, quint16 port)
{
dev_write->connectToHost(address, port);
dev_write->waitForConnected();
}
void BerUdp::setPortToRead(quint16 port)
{
dev_read->bind(port);
dev_read->open(QIODevice::ReadOnly);
bool ok = connect(dev_read, &QIODevice::readyRead,
this, &BerUdp::onReceive);
}
// Read new received data to my internal buffer
void BerUdp::onReceive()
{
bool av = dev_read->hasPendingDatagrams();
if (av)
{
int dSize = dev_read->pendingDatagramSize();
QByteArray dtg(dSize, 0);
dev_read->readDatagram(dtg.data(), dtg.size());
// write new data to the end
int buf_read_pos = m_buffer.pos();
m_buffer.seek(m_buffer.size());
m_buffer.write(dtg);
m_buffer.seek(buf_read_pos);
}
}
From the Qt documuntation on QIODevice::readData()
..When reimplementing this function it is important that this function
reads all the required data before returning. This is required in
order for QDataStream to be able to operate on the class. QDataStream
assumes all the requested information was read and therefore does not
retry reading if there was a problem...:
// Main read data function. There are only 4 bytes required, but maxSize == 0x4000 here:
qint64 BerUdp::readData(char *data, qint64 maxSize)
{
int n = m_buffer.read(data, maxSize);
// clear the data which has already read:
QByteArray& ba = m_buffer.buffer();
ba.remove(0, n); // m_buffer.size() == 0 after this
m_buffer.seek(0);
return n;
}
The problem is that after the first read I have empty buffer, and therefore my bytesAvailable() method returns 0:
qint64 BerUdp::bytesAvailable() const
{
qint64 my_size = m_buffer.size();
qint64 builtin_size = QIODevice::bytesAvailable();
return (my_size + builtin_size); // == 0 after 1st read
}
So I can not find out how many bytes are available, when use the class, for example:
BerUdp udp;
QDataStream stream;
stream.setDevice(&udp);
...
QIODevice* dev = stream.device(); // 19 bytes available here
if (dev->bytesAvailable() > 0) // == true
{
quint32 val;
stream >> val;
}
if (dev->bytesAvailable() > 0) // == false
{
//...
}
How can own wrapper of QUdpSocket be written correctly?
The idea of using intermediate buffer worked well, until I decided to move the logic to the separate QIODevice-derived class.
In the process of debugging with the Qt sources, it was found out that I should set the isSequential() property to true. Now my class works correct.
bool BerUdp::isSequential() const
{
return true;
}
Full class:
BerUdp.h
#pragma once
#include <QIODevice>
#include <QBuffer>
class QUdpSocket;
class QHostAddress;
class BerUdp : public QIODevice
{
Q_OBJECT
public:
BerUdp(QObject *parent = 0);
void startup();
void setHostToWrite(const QHostAddress &address, quint16 port);
void setPortToRead(quint16 port);
bool flush();
qint64 bytesAvailable() const;
bool waitForReadyRead(int msecs);
bool isSequential() const;
protected: // Main necessary reimplement
qint64 readData(char *data, qint64 maxSize);
qint64 writeData(const char *data, qint64 maxSize);
private slots:
void onReceive();
private:
void read_udp_datagram();
void write_new_data_to_buffer(QByteArray dtg);
private:
QUdpSocket* dev_write; // One udp socket to write
QUdpSocket* dev_read; // Another udp socket to read
// intermediate buffer to store received datagrams
// and to provide access to read- and QDataStream- operations
QBuffer m_buffer;
};
BerUdp.cpp
#include "BerUdp.h"
#include <QUdpSocket>
BerUdp::BerUdp(QObject *parent)
: QIODevice(parent)
{
startup();
}
// Initialization
void BerUdp::startup()
{
dev_write = new QUdpSocket(this);
dev_read = new QUdpSocket(this);
m_buffer.open(QIODevice::ReadWrite);
open(QIODevice::ReadWrite);
}
// Set a virtual connection to "host"
void BerUdp::setHostToWrite(const QHostAddress &address, quint16 port)
{
dev_write->connectToHost(address, port);
dev_write->waitForConnected();
}
// Bind a port for receive datagrams
void BerUdp::setPortToRead(quint16 port)
{
dev_read->bind(port);
dev_read->open(QIODevice::ReadOnly);
connect(dev_read, &QIODevice::readyRead,
this, &QIODevice::readyRead);
connect(dev_read, &QIODevice::readyRead,
this, &BerUdp::onReceive);
}
// Flush written data
bool BerUdp::flush()
{
return dev_write->flush();
}
// Returns the number of bytes that are available for reading.
// Subclasses that reimplement this function must call
// the base implementation in order to include the size of the buffer of QIODevice.
qint64 BerUdp::bytesAvailable() const
{
qint64 my_size = m_buffer.size();
qint64 builtin_size = QIODevice::bytesAvailable();
return (my_size + builtin_size);
}
bool BerUdp::waitForReadyRead(int msecs)
{
return dev_read->waitForReadyRead(msecs);
}
// Socket device should give sequential access
bool BerUdp::isSequential() const
{
return true;
}
// This function is called by QIODevice.
// It is main function for provide access to read data from QIODevice-derived class.
// (Should be reimplemented when creating a subclass of QIODevice).
qint64 BerUdp::readData(char *data, qint64 maxSize)
{
int n = m_buffer.read(data, maxSize);
// clear the data which has already been read
QByteArray& ba = m_buffer.buffer();
ba.remove(0, n);
m_buffer.seek(0);
return n;
}
// This function is called by QIODevice.
// It is main function for provide access to write data to QIODevice-derived class.
// (Should be reimplemented when creating a subclass of QIODevice).
qint64 BerUdp::writeData(const char *data, qint64 maxSize)
{
return dev_write->write(data, maxSize);
}
// Read new available datagram
void BerUdp::read_udp_datagram()
{
int dSize = dev_read->pendingDatagramSize();
QByteArray dtg(dSize, 0);
dev_read->readDatagram(dtg.data(), dtg.size());
write_new_data_to_buffer(dtg);
}
// Write received data to the end of internal intermediate buffer
void BerUdp::write_new_data_to_buffer(QByteArray dtg)
{
int buf_read_pos = m_buffer.pos();
m_buffer.seek(m_buffer.size());
m_buffer.write(dtg);
m_buffer.seek(buf_read_pos);
}
// Is called on readyRead signal
void BerUdp::onReceive()
{
bool available = dev_read->hasPendingDatagrams();
if (available)
{
read_udp_datagram();
}
}
I am trying to use multiple threads to request data from cloud. My problem is after the QnetworkReply finishes replyFinished(QnetworkReply*) slot never emitted. How do i do this ?
pc_gateway.h
//Main class
#include "dhvac_datacollector_thread.h"
class PC_Gateway : public QMainWindow
{
Q_OBJECT
DHVAC_DataCollector_Thread *m_DHVAC_DataCollector_Thread[70];
PC_Gateway(QWidget *parent = 0, Qt::WFlags flags = 0);
~PC_Gateway();
public slots:
void slot_start_comm();
};
pc_gateway.cpp
#include "pc_gateway.h"
PC_Gateway::PC_Gateway(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
}
PC_Gateway::~PC_Gateway()
{
}
void PC_Gateway::slot_start_comm()
{
int nNumOfThreads = 4;
for(int i=0; i<nNumOfThreads ; i++)
{
this->m_DHVAC_DataCollector_Thread[i] = new DHVAC_DataCollector_Thread(this);
this->m_DHVAC_DataCollector_Thread[i]->start();
}
}
DHVAC_DataCollector_Thread.h
//Thread class
class DHVAC_DataCollector_Thread : public QThread
{
Q_OBJECT
public:
DHVAC_DataCollector_Thread(QObject *parent);
~DHVAC_DataCollector_Thread();
void run();
void Stop();
public slots:
void replyFinished(QNetworkReply*);
};
DHVAC_DataCollector_Thread.cpp
#include "dhvac_datacollector_thread.h"
DHVAC_DataCollector_Thread::DHVAC_DataCollector_Thread(QObject *parent)
: QThread(parent)
{
}
DHVAC_DataCollector_Thread::~DHVAC_DataCollector_Thread()
{
}
void DHVAC_DataCollector_Thread::run()
{
while(true)
{
QString sUrl = "https://api.uno.taww.com/api/v2/data/sensor/"+sNodeId+"/10m/_";
QUrl url(sUrl);
bool bUrl = url.isValid();
if(!bUrl) //If URL is invalid
return false;
QNetworkRequest request;
request.setUrl(url);
request.setRawHeader("api_token","eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9");
request.setRawHeader("user_id","102473df5c9106e55d");
request.setRawHeader("cache-control","no-cache");
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)),this,
SLOT(replyFinished(QNetworkReply*)));
QNetworkReply *reply = manager->get(request);
}
}
void DHVAC_DataCollector_Thread::replyFinished(QNetworkReply *reply)
{
QByteArray responseData;
if(reply->error() == QNetworkReply::NoError)
{
responseData = reply->readAll();
QString sData (responseData);
reply->close();
reply->deleteLater();
qDebug()<<"Raw data:" <<sData;
}
}
You can try send your requests after receiving reply, in your replyFinished slot not in a loop. Just do one request, if replyFinished works fine that way then do the second request.
void DHVAC_DataCollector_Thread::replyFinished(QNetworkReply *reply)
{
QByteArray responseData;
if(reply->error() == QNetworkReply::NoError)
{
responseData = reply->readAll();
QString sData (responseData);
reply->close();
reply->deleteLater();
qDebug()<<"Raw data:" <<sData;
}
// nextRequest()
}
Also you have a leak. You are creating tons of QNetworkAccessManager and never releasing.
I'm using Qt and QProcess to read some data from other tools and printing them on my app. Think of it being a "terminal", for example.
I'm processing data using QProcess::canReadLine() and QProcess:readLine(), and that's wonderful. But some tools use \r to print progress bars on screen, and that's screwing with my parser. Since there is never some line to be read, my app just wait until the process finishes to print the last line: many lines glued together with \r instead of \n.
Anyways, is there someway to tell QProcess to use \r as linebreak also? I thought of implementing my QIODevice subclass, but I'd need to reimplement QProcess too, so that seems to be not the optimal approach.
I thought of using a middle buffer, and use this buffer to signal "hasLine" to my main program. I'd use QProcess::readyRead to populate the buffer, and then the buffer to populate my main app, but I'd like to just tell Qt that a \r is also OK as a linebreak. Is that possible?
I don't think it's possible to directly tell Qt to use '\r' as a linebreak. I thought that QTextStream could do that, but looking at its sources right now it seems to me that I was wrong.
One funny way of doing it would be to implement a custom QIODevice subclass that reads from another QIODevice and just replaces all '\r's with '\n's, delegating all other methods excep read() varieties to the original device. Then readLine() and QTextStream would work on the resulting stream just fine, I think. You'd have to deal somehow with the possible '\r\n' sequence, though. The upside is that you don't have to do any buffering in that class.
Something along these lines:
class CRFilter: public QIODevice {
Q_OBJECT
public:
CRFilter(QIODevice *device);
protected:
virtual qint64 readData(char *data, qint64 maxSize);
virtual qint64 writeData(const char *data, qint64 maxSize);
private:
QIODevice *device;
};
CRFilter::CRFilter(QIODevice *device):
device(device)
{
// delegate the readyRead() signal to this object
connect(device, SIGNAL(readyRead()), SIGNAL(readyRead()));
// and maybe other signals like bytesWritten() too...
}
qint64 CRFilter::readData(char *data, qint64 maxSize)
{
qint64 res = device->read(data, maxSize);
for (qint64 i = 0; i < res; i++) {
if (data[i] == '\r')
data[i] = '\n';
}
return res;
}
qint64 CRFilter::writeData(const char *data, qint64 maxSize)
{
return device->write(data, maxSize);
}
Then you just do this:
QProcess process; // use QProcess methods on this
CRFilter reader(&p); // use QIODevice methods on this
reader.open(QIODevice::ReadWrite); // need this to convince read()/write() methods to work
I hadn't actually tested it, so it probably needs some debugging to get it right. I also think it's a bit ugly, but can't think of any really elegant solution.
Since I'm not using polymorphism with this, no problem inheriting publicly and overriding some methods and signals:
QCLIProcess.h
#ifndef QCLIPROCESS_H
#define QCLIPROCESS_H
#include <QProcess>
class QCLIProcess : public QProcess
{
Q_OBJECT
public:
explicit QCLIProcess(QObject *parent = 0);
bool canReadLine() const;
QString readLine();
signals:
void readyRead();
private slots:
void processLine();
private:
QByteArray buffer;
QStringList lines;
};
#endif // QCLIPROCESS_H
QCLIProcess.cpp
#include "QCLIProcess.h"
#include <QtCore>
QCLIProcess::QCLIProcess(QObject *parent) :
QProcess(parent)
{
setReadChannelMode(QProcess::MergedChannels);
connect((QProcess *)this, SIGNAL(readyRead()), this, SLOT(processLine()));
}
void QCLIProcess::processLine(){
buffer.append(readAll());
int last = 0;
for(int i=0; i<buffer.size(); i++){
if (buffer.at(i) == '\n' || buffer.at(i) == '\r'){
QString line(buffer.mid(last, i-last));
line.append('\n');
if (!line.isEmpty()) lines << line;
last = i+1;
}
}
buffer.remove(0, last);
emit readyRead();
}
bool QCLIProcess::canReadLine() const {
return !lines.isEmpty();
}
QString QCLIProcess::readLine(){
QString line;
if (!lines.isEmpty()){
line = lines.at(0);
lines.removeFirst();
}
return line;
}
UPDATE:
I ended encapsulating the QProcess in a new class, rather than deriving it. This way I could control which signals and which slots I want to expose.
QLineBufferedCRFilteredProcess.h
#ifndef QCLIPROCESS_H
#define QCLIPROCESS_H
#include <QProcess>
class QLineBufferedCRFilteredProcess : public QObject
{
Q_OBJECT
public:
explicit QLineBufferedCRFilteredProcess(QObject *parent = 0);
bool canReadLine() const;
QString readLine();
void start(const QString &program, const QStringList &arguments);
void close();
signals:
void readyRead();
void finished(int exitCode, QProcess::ExitStatus exitStatus);
private slots:
void processLine();
private:
QProcess process;
QByteArray buffer;
QStringList lines;
};
#endif // QCLIPROCESS_H
QLineBufferedCRFilteredProcess.cpp
#include "QLineBufferedCRFilteredProcess.h"
#include
QLineBufferedCRFilteredProcess::QLineBufferedCRFilteredProcess(QObject *parent) :
QObject(parent)
{
process.setReadChannelMode(QProcess::MergedChannels);
connect(&process, SIGNAL(readyRead()), SLOT(processLine()));
connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), SIGNAL(finished(int,QProcess::ExitStatus)));
}
void QLineBufferedCRFilteredProcess::processLine()
{
buffer.append(process.readAll());
int last = 0;
for(int i=0; i<buffer.size(); i++){
if (buffer.at(i) == '\n' || buffer.at(i) == '\r'){
QString line(buffer.mid(last, i-last));
line.append('\n');
if (!line.isEmpty()) lines << line;
last = i+1;
}
}
buffer.remove(0, last);
emit readyRead();
}
bool QLineBufferedCRFilteredProcess::canReadLine() const
{
return !lines.isEmpty();
}
QString QLineBufferedCRFilteredProcess::readLine()
{
QString line;
if (!lines.isEmpty()){
line = lines.at(0);
lines.removeFirst();
}
return line;
}
void QLineBufferedCRFilteredProcess::start(const QString &program, const QStringList &arguments)
{
process.start(program, arguments);
}
void QLineBufferedCRFilteredProcess::close()
{
process.close();
}