I want to read a 50MB file and send it over tcp. The file contains only floats. First I created only a Mainwindow, witch reads one line and sends it to the Server, but the gui got frozen. So I created a class that depends on QThread called QSendThread. Here is the Code for the class QThread:
#ifndef QSENDTHREAD_H
#define QSENDTHREAD_H
#include <QThread>
#include <QLabel>
#include <QFile>
#include <QMessageBox>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
class QSendThread : public QThread
{
Q_OBJECT
public:
QSendThread(QTcpSocket* qtcpso, QLabel* qlbl, QFile* qfiel, QObject *parent = NULL);
~QSendThread();
protected:
void run(void);
private:
QTcpSocket* qtcpsoDest;
QLabel* qlblRef;
QFile* qfileRef;
signals:
void error(QString qstrError);
};
#endif // QSENDTHREAD_H
#include "qsendthread.h"
QSendThread::QSendThread(QTcpSocket* qtcpso, QLabel* qlbl, QFile* qfile, QObject *parent)
: QThread(parent)
{
qtcpsoDest = qtcpso;
qlblRef = qlbl;
qfileRef = qfile;
}
QSendThread::~QSendThread()
{
}
void QSendThread::run(void)
{
int iLine = 0;
do
{
QByteArray qbarrBlock;
QDataStream qdstrmOut(&qbarrBlock, QIODevice::WriteOnly);
// show witch line is read
qlblRef->setText(tr("Reading Line: %1").arg(++iLine));
qdstrmOut.setVersion(QDataStream::Qt_4_6);
qdstrmOut << (quint16)0;
qdstrmOut << qfileRef->readLine().data();
qdstrmOut.device()->seek(0);
qdstrmOut << (quint16)(qbarrBlock.size() - sizeof(quint16));
qtcpsoDest->write(qbarrBlock);
qtcpsoDest->flush();
qbarrBlock.clear();
} while(!qfileRef->atEnd());
}
But the program crashing in the method qregion::qt_region_strictContains(const QRegion ®ion, const QRect &rect)
Is the method to read the file like I am doing wrong?
Thanks for Help.
First, you shouldn't really need to subclass QThread. The Qt documentation is misleading on this point. See this accepted answer for a similar question for lots of good info.
Second, you can only correctly access the gui from the main thread so your call qlblRef->setText() would be a problem. Accessing the gui from a thread other than the main one can be done using signals and slots or postEvent(). You can read up on events here.
Finally, this documentation is really required reading for working with threads in Qt. Pay particular attention to the section on threads and QObjects.
Addition:
To follow the advice above, you could certainly wrap your file reading code in a QObject subclass. An alternative (which I have little experience with myself) may be to try putting your code in QtConcurrent::run() and getting the result with a QFuture.
Related
I need some help understanding how to access the QT GUI ui from another class/another cpp file.
Background: I am working on a project that consists of many cpp and hpp files. I am not the original author. This project is to control a USRP to receive/send data....with various parameters. Originally, you had to manually change parameter values inside several cpp files (i..e start frequency, steps, duration of receive, etc). Then re-compile and then run the executable. I wrote a simple Qt GUI interface in the main.cpp function where the users would enter in the GUI basic usrp receive parameters. Then the GUI interface would pass these values back into the uspr function that would actually execute the USRP functionality. This part is actually working great and I am happy (my first GUI!, Yay!)
One thing that I would like to do is to also display the current frequency in the main GUI window via the LCDNumber widget. This frequency is managed by another class, in another cpp file.
Here is what I tried:
Attempt #1: Make the MainWindow ui publicly available int the class/cpp file where the Frequency is established:
freq_transmit.cpp:
......
#include "mainwindow.hpp"
#include "ui_mainwindow.hpp"
.....
void Receiver::run()
{
//bunch of lines of code about USRP stuff
.....
rxCenterFreq // <---variable that holds the current frequency (which changes every second)
ui->lcdnumber->display(rxCenterFreq); // <-- -compiler error: ui not declared in this scope
............
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCore>
#include <QCoreApplication>
#include <QPalette>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
Ui::MainWindow *ui;
QPalette temp_red;
QPalette temp_green;
private slots:
void on_button_CalcSchedule_clicked();
void on_button_Reset_clicked();
void execute_run_usrp();
void on_button_QUIT_clicked();
void on_AutoSchedulerCheckBox_stateChanged(int arg1);
void on_button_manul_CalcSchedule_clicked();
void on_button_EXECUTE_clicked();
void on_button_SeeSchedule_clicked();
void on_button_STOP_clicked();
void function_test();
public slots:
void updateTXFreq(double a);
private:
void reset_sweep_values();
std::string calc_schedule_start_time(int minute_cadence);
void calc_cadence();
double calc_sweep_duration();
int nearest_cadence(int numToRound, int multiple);
signals:
void send_start_schedule(std::string, double, int, int);
};
#endif // MAINWINDOW_H
Attempt #2: Use Qt CONNECT functionality:
Step 1: generate a SIGNAL / emit function in the freq_transmit.hpp header:
....
signals:
void sendTXFreq(double a);
Step 2: Enter this emit signal in the freq_transmit.cpp file where the Frequency is being generated:
freq_transmit.cpp:
......
#include "mainwindow.hpp"
#include "ui_mainwindow.hpp"
.....
void Receiver::run()
{
//bunch of lines of code about USRP stuff
.....
emit sendTXFreq(rxCenterFreq); // emit signal to QT
....
Step 3: Declare a SLOT in mainwindow.h to accept emitted signal
mainwindow.hpp:
...
public slots:
void updateTXFreq(double a);
Step 4: Implementation:
mainwindow.cpp:
....
void MainWindow::updateTXFreq(double a)
{
ui->lcdnumber->display(a);
}
connect(&Receiver, &Receiver::sendTXFreq, this, &MainWindow::updateTXFreq); // <-- error: expected primary expression before ','
which is the comma after "&Receiver", which is a class that has various functions in it, including the Receiver::run() where Frequency is generated.`
Long story short, I am trying to have the generated frequency linked to a LCDNumber widget so that it shows on the GUI the value of frequency as the USRP code runs.
PS: I am not an expert C++ coder, I am just now learning about classes and QT GUI. Somebody mentioned that I should "create a pointer of my MainWindow in the freq_transmit.cpp file" so that then I can accesss ui elements direclty in that class, but I thought I tried that with ui->lcdnumber->display(rxCenterFreq);
Any guidance much appreciated and thank you!
I have been new to the Qt environment. I recently started with a QtCreator project for a simple chat application (QMainWindow). I have nearly completed the project but stuck with the SIGNAL/SLOT problem.
Let me explain my problem in brief :
Due to the length of the code I am not able to paste it here.
I have two classes MainWindow and NetworkFile.
The function newServerConn() in NetworkFile connects the signal readyRead() to the slot readFromClient().
The string returned by client is stored in a QString in readFromClient() SLOT.
Problem:
I have to return the QString in the slot to the newServerConn() function and from there to a function in MainWindow class because only then I would be able to print the string to the plainLineEdit widget pointed by the ui object.
Question 1:
How can I return a value from the slot?
Question 2:
Or is there any way I could get a copy of the ui instance in the NetworkFile class so that I could use the widgets from there?
Thanks.
I would just emit the data as a signal and wire up the connection between that new signal and a slot where you add then string to your ui.
A quick self-contained example (which btw. "Due to the length of the code I am not able to paste it here." is just an excuse, you can pretty much always cut down your relevant code)
Header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTextEdit>
class NetworkFile;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow(){}
public slots:
void addText(QString str)
{
edit->append(str);
}
private:
QTextEdit* edit;
NetworkFile* net;
};
class NetworkFile : public QObject
{
Q_OBJECT
public:
NetworkFile(QObject *parent = 0):
QObject(parent)
{
connect(&server, &QTcpServer::newConnection,
this, &NetworkFile::newConnection);
//TODO: check return value
server.listen(QHostAddress::Any,16001);
}
signals:
void dataRead(QString);
public slots:
void newConnection(){
//TODO: wire up socket disconnect with deleteLater, also check for null
QTcpSocket* socket = server.nextPendingConnection();
connect(socket, &QTcpSocket::readyRead,
this, &NetworkFile::dataAvailable);
}
void dataAvailable(){
//HACK: only for brevity, create a connection wrapper that contains the socket in real code
QTcpSocket* source = (QTcpSocket*)sender();
auto bytes = source->readAll();
if(bytes.size())
{
emit dataRead(QString(bytes));
}
}
private:
QTcpServer server;
};
#endif // MAINWINDOW_H
cpp file
#include "mainwindow.h"
#include <QApplication>
MainWindow::MainWindow(QWidget *parent ):
QMainWindow(parent)
{
edit = new QTextEdit(this);
net = new NetworkFile(this);
connect(net, &NetworkFile::dataRead,
this, &MainWindow::addText );
setCentralWidget(edit);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
As from the documentation:
Signals [...] can never have return types (i.e. use void).
Therefore slot return types are useless when invoked through a signal (even though you can still use them when you invoke a slot directly, ie if it's a member function).
That being said, you can capture ui or even better plainLineEdit by reference or by address in your slot (ie if it's a lambda) and set correctly the string from there.
I'm new to StackOverflow and wondering if I'm doing this right:
I'm writing a simple Qt application to test multi-threading (something I am also completely new to). I made a MainWindow that contains widgets, and a class MyThread that subclasses QThread and overrides the run() method.
The application simply displays two buttons, "Start Counter" and "Stop Counter", and a text field. When "start counter" is pressed, a worker thread is created and runs in the background, continuously incrementing a counter in a while loop and signaling the main thread (where the GUI is) with the updated value. When "Stop Counter" is pressed, a signal is sent to the main thread that stops the while loop, and the counter is stopped until "Start Counter" is pressed again.
This works perfectly fine ... but is it the best way? I'm new at this, and read a lot of people saying "don't subclass QThread" and other people saying "subclass QThread", and it's a little bit confusing. If this isn't the best way to implement this sort of thing (run a computationally-intensive loop in a background thread with "start" and "stop" buttons), what is? If I'm doing it wrong, how do I do it right? I don't want to learn the wrong way.
Thank you! And here's the code:
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public slots:
void stopRunning();
protected:
virtual void run();
signals:
void signalValueUpdated(QString);
private:
bool isRunning;
};
MyThread.cpp
#include "MyThread.h"
#include <QString>
void MyThread::run()
{
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
static int value=0; //If this is not static, then it is reset to 0 every time this function is called.
isRunning = 1;
while(isRunning == 1)
{
QString string = QString("value: %1").arg(value++);
sleep(1/1000); //If this isn't here, the counter increments way too fast and dies, or something; the app freezes, anyway.
emit signalValueUpdated(string);
}
}
void MyThread::stopRunning()
{
isRunning = 0;
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include "MyThread.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
//Widgets
QHBoxLayout * boxLayout;
QPushButton * startButton;
QPushButton * stopButton;
QLineEdit * lineEdit;
MyThread thread;
};
#endif
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
boxLayout = new QHBoxLayout(this);
startButton = new QPushButton("Start Counter", this);
stopButton = new QPushButton("Stop Counter", this);
lineEdit = new QLineEdit(this);
boxLayout->addWidget(startButton);
boxLayout->addWidget(stopButton);
boxLayout->addWidget(lineEdit);
qDebug("Thread id %d",(int)QThread::currentThreadId());
//When the start button is pressed, invoke the start() method in the counter thread
QObject::connect(startButton,SIGNAL(clicked()),&thread,SLOT(start()), Qt::QueuedConnection);
//When the stop button is pressed, invoke the stop() method in the counter thread
QObject::connect(stopButton,SIGNAL(clicked()),&thread,SLOT(stopRunning()), Qt::QueuedConnection);
//When the counter thread emits a signal saying its value has been updated, reflect that change in the lineEdit field.
QObject::connect(&thread,SIGNAL(signalValueUpdated(const QString&)),lineEdit,SLOT(setText(const QString&)), Qt::QueuedConnection);
}
Most of the time QThread sub-classing is a wrong way to do threading in Qt. I suggest you to read an article about threads, event loops and other which could give you an idea how to use threads in Qt in a better way. But do not listen to anyone who arguing that there is the only one right way to use QThread. There are 2 ways and while subclassing is not needed in general it could be useful sometimes. You just need to use non-subclassing way until you really need to subclass. In your particular case you don't need subclassing.
Replace sleep(1/1000); with msleep(100); Things will be just fine :)
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)."
I'm trying to download a page from a server to my QT program, but I've been searching ways to do it and they don't really work a lot. I'm not an expert in QT/C++, so be kind :)
Well.. So far I come with this code:
[OLD CODE] - Check the updated code bellow!
http.cpp
#include "http.h"
http::http(QObject *parent) :
QObject(parent)
{
qDebug() << "HTTP ST";
http1 = new QHttp(this);
connect(http1, SIGNAL(done(bool)), this, SLOT(httpdown())); // Correction 1.
http1->setHost("localhost");
http1->get("/test.php");
qDebug() << "HTTP END";
}
void http::httpdown()
{
qDebug() << "completed!";
qDebug() << http1->readAll();
}
http.h
#ifndef HTTP_H
#define HTTP_H
#include <QtNetwork>
#include <QHttp>
#include <QDebug>
#include <QObject>
class http : public QObject
{
Q_OBJECT
public:
explicit http(QObject *parent = 0);
signals:
public slots:
void httpdown();
private:
QHttp *http1;
};
#endif // HTTP_H
Well the problem is that httpdown() is never called, and I've tried anything I know :( Probably I'm not doing this correctly.
Help will be much appreciated.
Thanks.
QUESTION UPDATE
I've ear the suggestion of alexisdm and to check QNetworkAccessManager. So here it is new code working on the main() correctly.
When I run it from another class I never get the signal.
[NEW CODE]
http2.cpp
#include "http2.h"
http2::http2(QObject *parent) :
QObject(parent)
{
m_manager = new QNetworkAccessManager(this);
connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(httpdown(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl("http://localhost/test.php"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
m_manager->get(request);
}
void http2::httpdown(QNetworkReply* result)
{
QByteArray data= result->readAll();
QString str(data);
qDebug() << str;
}
http2.h
#ifndef HTTP2_H
#define HTTP2_H
#include <QObject>
#include <QDebug>
#include <QtNetwork>
#include <QNetworkReply>
class http2 : public QObject
{
Q_OBJECT
public:
explicit http2(QObject *parent = 0);
signals:
public slots:
void httpdown(QNetworkReply* result);
private:
QNetworkAccessManager* m_manager;
};
#endif // HTTP2_H
Now if I call it directly under main.cpp like this:
main.cpp
#include <QtCore/QCoreApplication>
#include "tcpserver.h"
#include "http2.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
http2 h; // --> Working!!
tcpserver mServer;
return a.exec();
}
It works fine. However if I call it inside the tcpserver class like this:
tcpserver.cpp
#include "tcpserver.h"
#include "protocol.h"
#include "http2.h"
QTextStream in(stdin);
tcpserver::tcpserver(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
[ ... Other Server Stuff ... ]
// http2 h; // --> OLD CODE - Not Working :(
http2 *h = new http2(this); // **--> NEW CODE working provided by alexisdm**
}
The signal never happens... What's wrong? I'm new here! :P
Anyway, alexisdm said: "Maybe the http object gets destroyed before the signal can be emitted (if it was allocated on the stack for example)" - Solution accepted, code bellow corrected Read this: QT C++ - QNetworkAccessManager help needed! Class problem (link to answer)
What should I do to avoid that?
Thanks! ;)
Your http or http2 object is destroyed at the end of the constructor, because it is allocated locally.
You should at least allocate it dynamically:
http2 *h = new http2(this);
If you want to reuse it, you can also declare it as a member of tcpserver, instead of using a local variable. If not, you should destroy it somehow when it is not needed anymore.
Edit
If the destruction is done within the slot and/or in response to a signal from h, you should use QObject::deleteLater rather than an immediate delete, because the object might still be referenced somewhere at the time the signal is emitted. So either deleteLater(); in httpdown() or h->deleteLater(); in a tcpserver slot.
To know if you have an answer or an error you could use that code and forward either the data or the error to your tcpserver class with custom signal(s) and slot(s).
The line:
SIGNAL(bool)
really doesn't look right; did you mean
SIGNAL(done(bool))
?
In debug mode, there should be some debug output saying that it could not connect the signals.