processEvents And Memory Leak? - c++

NOTE: THE CODE PROVIDED JUST GIVES THE IDEA OF THE STRUCTURE OF THE APPLICATION
I have a Qt application, interfacing with external hardware. The structure is such that the class for interfacing with the hardware inherits from QObject and is composed with the main GUI thread class. Let's say the class is test.h, here is its sample code:
#ifndef TEST_H
#define TEST_H
#include <QLineEdit>
#include <QString>
#include <QTimer>
#include "ui_test.h"
#define TIMEOUT 100
class TestObj;
class TestApp:public QWidget, public Ui::mTestForm
{
Q_OBJECT
public:
TestApp(QWidget* parent=0);
QTimer* mTimer;
bool mWindowClosed;
TestObj* mObj;
public slots:
void UpdateText();
void Exit();
};
class TestObj:public QObject
{
Q_OBJECT
public:
TestObj();
void RandomTest();
};
#endif
Code for test.cpp is
#include "test.h"
TestApp::TestApp(QWidget* parent):QWidget(parent)
{
setupUi(this);
mObj = new TestObj();
mWindowClosed=false;
mLineEdit->setText("Hello");
mTimer=new QTimer();
mTimer->singleShot(1000,this,SLOT(UpdateText()));
connect(mExitButton,SIGNAL(clicked()),this, SLOT(Exit()));
}
void TestApp::UpdateText()
{
if(mWindowClosed)
{
//QApplication::processEvents();
return;
}
else
{
//QApplication::processEvents();
mObj->RandomTest();
mLineEdit->setText("Hi");
mTimer->singleShot(100,this,SLOT(UpdateText()));
}
}
void TestApp::Exit()
{
mWindowClosed=true;
}
Now consider that TestObj class is the one used to interface with the hardware. This class sends three possible commands (in actual code, the above is just a sample structure) with different timeouts to the hardware, thus we have a timer which is used when sending commands (implemented as functions) to the hardware. Each of these has a processEvents entry to identify any changes to variables in the meanwhile.
The problem is this module is responsible for a steady rise in memory during program execution.
When I comment out the UpdateText() function in the TestApp constructor, the app works fine.
My guess is that most likely there is queuing of signal slots due to which the memory increase, because there are lots of GUI events taking place. And since the class isn't implemented as a separate thread and clubbed with the main GUI thread. There is continuous update of the main thread.
Can someone suggest a way out? I don't have the authority to change the design otherwise I would have implemented the interface class as a thread. So if a solution can be suggested with the current design as is, it would be beneficial.

Creating a regular timer, setting its interval to 100 and connecting its timout signal to the
UpdateText function will avoid events piling up.
P.S: You don't need a QTimer object for singleShot, you can call QTimer::singleShot directly.

Wild guess:
Try changing this:
mTimer->singleShot(100,this,SLOT(UpdateText()));
to this:
if (!slotSet)
{
mTimer->singleShot(100,this,SLOT(UpdateText()));
slotSet = true;
}

Related

Accessing Qt GUI ui from another class OR using connect() to update gui elements

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!

Create QMainWindow from different thread

I try to create something like a window pool. You can use these windows everywhere in your program to display graphics and plot diagrams etc. The widgets working well but the main problem at the moment is the frustrated tries, to create the pool. One non QObject-Object should represent a QMainWindow to cut the bindings to Qt.
I cannot create a widget -> I tried invokeMethode, connect and QTimer but nothing works. Sometimes the methods donĀ“t get called or I am not in the gui thread... Any idea?
Edit 2 - new version:
header:
#pragma once
#include <QMainWindow>
#include <QTimer>
class MyWindow : QObject
{
Q_OBJECT
public:
MyWindow();
};
class QWindowPool : public QObject
{
Q_OBJECT
public:
QWindowPool();
public slots:
void createWindow();
};
class QWindow : public QMainWindow
{
Q_OBJECT
};
cpp:
#include
#include <QApplication>
#include <QTimer>
#include <QtConcurrent/qtconcurrentrun.h>
#include <iostream>
#include <future>
static QWindowPool *pool = new QWindowPool();
QWindowPool::QWindowPool() {
// check if app is running
if (!QApplication::instance()) {
bool appOnline = false;
QtConcurrent::run([&appOnline](){
int c = 0;
new QApplication(c, NULL);
appOnline = true;
qApp->exec();
});
while (!appOnline) {}
}
moveToThread(QApplication::instance()->thread());
}
void QWindowPool::createWindow() {
printf("window created\n");
new QWindow();
}
MyWindow::MyWindow() {
QTimer::singleShot(0, pool, SLOT(createWindow()));
}
int main()
{
MyWindow mw;
std::thread t1([](){
MyWindow mw;
std::thread t2([](){
MyWindow mw;
});
t2.join();
});
t1.join();
std::cin.ignore();
return 0;
}
Now the code do what is should. I can create widgets in different threads. But there are two scenarios, where I would stack at:
Someone (anyone who would like to use this library) creates before me QApplication and never calls qApp->exec
Someone want to create an own UI with Widget but does not work in my qt::concurrent gui thread. He would probably not get along with this.
What I want is in the final application:
The user should get the possibility to write anywhere in his code and in any thread:
MyWindow mw(dataToDisplay)
and the window should be created and showed to him.
Qt will only let you create widgets from the main GUI thread, this is explicitly mentioned in the docs (emphasis mine):
As mentioned, each program has one thread when it is started. This
thread is called the "main thread" (also known as the "GUI thread" in
Qt applications). The Qt GUI must run in this thread. All widgets and
several related classes, for example QPixmap, don't work in secondary
threads. A secondary thread is commonly referred to as a "worker
thread" because it is used to offload processing work from the main
thread.

Error with QObject::connect()

I am trying to run QTimer and have it warn me when timeouting. To do so, I use slot and signal to link the two.
The guy.h:
#ifndef GUY_H
#define GUY_H
#include <QGraphicsItem>
#include <QTimer>
#include <QObject>
class Guy : public QGraphicsItem
{
public:
Guy(int x, int y);
void timerStart();
public slots:
void onTimeOutTimer();
[...]
QTimer *timer;
}
#endif // GUY_H
The guy.cpp:
#include "guy.h"
#include <QTimer>
#include <QObject>
#include <stdio.h>
#include <iostream>
Guy::Guy(int x, int y)
{
timer = new QTimer();
}
void Guy::timerStart()
{
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(onTimeOutTimer()));
this->timer->setInterval(1000);
this->timer->start();
std::cout << "starting timer" << std::endl;
}
void Guy::onTimeOutTimer()
{
std::cout << "check" << std::endl;
}
But as an ouput, I get this error:
No matching function for call to 'QObject::connect(QTimer*&, const char*, Guy* const, const char*)'
As I undertsand it is that QTimer is no QObject required as first input of the function connect(), but the documentation specifies QTimer inherits from QObject.
I have no clue here.
You will need to inherit from QObject, too, to get this working as signals and slots are availabl for QObjects. QGraphicsItem does not inherit QObject, not even indirectly.
Not only that, you will also need to add the Q_OBJECT macro as follows:
class Guy : public QObject, public QGraphicsItem
{
Q_OBJECT
...
}
or even better because QGraphicsObject inherits QObject and QGraphicsItem.
...
#include <QGraphicsObject>
...
class Guy : public QGraphicsQObject
{
Q_OBJECT
...
}
Also, if you make this change, I suggest to change the QObject::connect to connect as you do not need to indicate the QObject:: scope then.
On a side note, including stdio.h does not seem to make sense here.
Furthermore, allocating the QTimer instance on the heap looks like wasteful to me. It is not only leaking the memory, but also adds additional complexity. Even if you allocate it on the heap, you should pass this as the parent and use the initializer list or C++11 style initialization. Also, if you allocate it on the heap, you could use forward declaration in the header.
If the slot is not used outside the class, you should also make that private.
It is probably also a bad idea to make the timer member public. Hopefully you do not do that.
You can inherit from QGraphicsObject which provides a base class for all graphics items that require signals, slots and inherits QGraphicsItem and QObject. Also add Q_OBJECT macro in your class declaration.
If you use new Qt5 style connects as in
QObject::connect(timer, &QTimer::timeout, this, &Guy::onTimeOutTimer)
The onTimeOutTimer function does not need to be marked as slot, and Guy could stay a non-QObject. Much slimmer and less macros involved.

Using Qt's signals in a non Qt application (C++)

I have a lot of existing code using Qt, and more specifically Qt signals and slots to time specific actions.
Now I need to use this code within a new application which is not a Qt application (and cannot be - I am writing a plugin to visual studio). Anyway - how can I get the existing code to actually intercept the signals and activate the relevant slots?
Do I need to somehow create a dummy Qt application? If so - how do I cause it to process the signals without becoming a blocking loop to the rest of my code?
It seems that if you write something like this, the "Test" message is still printed even though there is no event loop, so this could be a clue:
#include <QObject>
#include <QCoreApplication>
#include <QDebug>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent) : QObject(parent) {}
void testMethod() { emit testSignal(); }
signals:
void testSignal();
public slots:
void testSlot() { qDebug() << "Test"; }
};
#include "main.moc"
int main(int argc, char **argv)
{
// QCoreApplication coreApplication(argc, argv);
MyClass myObject(0);
QObject::connect(&myObject, SIGNAL(testSignal()), &myObject, SLOT(testSlot()));
myObject.testMethod();
// return coreApplication.exec();
return 0;
}
This way, you would still need Qt, but you could avoid having a "blocking" event loop. However, it might be simpler to just rearrange the code from the signal-slot layering to direct calls, depending on how many direct calls you would need to do for a signal emitted.
This is a common problem when using ASIO and Qt together. The solution I have found is to make a Broker object, and run the Qt and ASIO loops on their own threads. The Broker is the target for emit calls to the ASIO message queue, and the emitter to the Qt message queue. Take care of the syncronisation/data copying in the Broker.

Application crash on new thread starts

why this application crashes on new thread starts, please somybody point out me have i done enything wrong..
newthread.h
#ifndef NEWTHREAD_H
#define NEWTHREAD_H
#include <QThread>
class newthread: public QThread
{
public:
newthread();
public slots:
void run();
};
#endif // NEWTHREAD_H
newthread.cpp
#include "newthread.h"
#include "mainwindow.h"
#include<QDebug>
newthread::newthread()
{
}
void newthread::run(){
qDebug()<<"thread executed";
}
mainwindow.cpp
#include <QtGui>
#include "mainwindow.h"
#include"newthread.h"
MainWindow::MainWindow(QWidget *parent)
{
setupUi(this);
connect(pushButton,SIGNAL(clicked()),this, SLOT(opthread()));
}
void MainWindow::opthread(){
newthread th;
th.start();
}
here in the main window there is a public slot called ophthread(). as shown above when a button in the main window is pressed that slot will trig. in it i i declared a newthread object called th and th.start() to start it. have i done enything wrong.
this compilles without errors. but when run the binary it gives a error and crashes.
my second question is if i need the thread to write some text on a textEdit in the main window how to do that. is it possible newthread class access objects in the mainwindow class.
void MainWindow::opthread(){
newthread th;
th.start();
}
You are creating the thread object on the stack. He will be destroyed when the function opthread returns. And from the Qt documentation :
Deleting a running QThread (i.e. isFinished() returns false) will
probably result in a program crash. Wait for the finished() signal
before deleting the QThread.
You need to provide a greater lifespan for your newthread object. waiting for it to be finished is not an option, as it will result in a sequential execution. Either you use class members or you allocate your thread objects on the heap.
Personal opinion:
Not only sub-classing QThread is not the most appropriate method of getting it done, I believe you don't need a thread at all.
As you're creating the thread with: -
newthread th;
It will then go out of scope and get deleted, which is not what you're wanting.
You need to dynamically create the object: -
newthread* th = new newthread;