PDA

View Full Version : How can a delete a widget after it emits a signal



Linwood
8th March 2017, 19:32
This is a bit convoluted. I have sample code but the sample code does not indicate why I am trying to do this, and that perhaps merits a few words.

I have an application running in a very memory limited Raspberry Pi. It puts up a large table of information for someone to select a row. Once selected, I want to actually delete that QTableWidget to save memory.

The code that did this was fairly convoluted but fundamentally did this: The click on the table emitted a signal to a containing widget (about 3 layers of parents up), which in turn hide another parent (about 2 layers up), and in the hideEvent of the parent of the QTableWidget I am deleting the QTableWidget.

It appears what happens is when the slot used for the clicked signal completes, a segfault occurs. The signal is not queued (apparently) but executes immediately like a call.

I have tried various ways to rearrange the code to no avail (well, short of something like a timer).

Below is code that removes all the custom widgets and nesting and does results. It looks a bit silly but does demonstrate the segfault. The output from running this is below, and as you can see the signal executes the slot ... in terms of timing... in line, so the delete of the QTableWidget is deleted before exiting the SLOT from the cellClicked.



onchosen
doSignal
Exiting doSignal
after aSignal
The program has unexpectedly finished.


What appears needed is to somehow get the delete out of the onchosen() function's call (or more precisely have it called after onchosen() exits, even though caused by onchosen(). And short of a timer I do not see how (and a timer seems... chancy, might I get race conditions that cause problems).

Is there a proper approach to having a click on a table (ultimately) result in the table being deleted?



#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTableWidget>
#include <QDebug>

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);
~MainWindow();

private:
QTableWidget* qt;

private slots:
void onchosen(int, int);
void doSignal();

signals:
void aSignal();
};

#endif // MAINWINDOW_H





#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}




#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
qt = new QTableWidget(2,1,this);
qt->setItem(0,0,new QTableWidgetItem("stuff00"));
qt->setItem(1,0,new QTableWidgetItem("stuff10"));
qt->setFixedSize(600,600);
this->setFixedSize(900,900);
qt->show();
connect(qt,SIGNAL(cellClicked(int,int)),this,SLOT( onchosen(int,int)));
connect(this,SIGNAL(aSignal()),this,SLOT(doSignal( )));
}

void MainWindow::onchosen(int r, int c)
{
qDebug() << "onchosen";
emit aSignal();
qDebug() << "after aSignal";
}

void MainWindow::doSignal()
{
qDebug()<<"doSignal";
delete qt; // If not present the program will not fail
qDebug()<<"Exiting doSignal";
}

MainWindow::~MainWindow()
{

}

Santosh Reddy
9th March 2017, 03:58
Well it's not generally recommended to delete the signal sender object, but in practice it is sometime very handy to do so, for such cases you should be using deleteLater(). If you want to delete after cellClicked signal than you could do like this, note the sequence is important, and make sure you don't connect any slot to that object after connecting deleteLater()


connect(qt,SIGNAL(cellClicked(int,int)),this,SLOT( onchosen(int,int)));
connect(qt,SIGNAL(cellClicked(int,int)),qt,SLOT(de leteLater())); // and no need to delete the qt object in the slot
connect(this,SIGNAL(aSignal()),this,SLOT(doSignal( )));


another alternate



void MainWindow::doSignal()
{
qDebug()<<"doSignal";
//delete qt; // If not present the program will not fail
qt.deleteLater();
qDebug()<<"Exiting doSignal";
}

anda_skoa
9th March 2017, 08:37
The signal is not queued (apparently) but executes immediately like a call.

A signal/slot connection is like a direct method call by default in a single threaded context.

Signal/Slot connections are only "queued" calls if [noparse]Qt::QueuedConnection[/norparse] is explicitly used as the connection type or the signal is emitted by a different thread than the thread responsible for the receiver object's events.

As Santosh Reddy suggested, just call the object's deleteLater() instead of invoking its delete operator.

Cheers,
_

Linwood
9th March 2017, 15:06
Thank you.

Sigh.... when I was first reading about QT5 I read about deleteLater(), and then promptly purged it from my memory. Yes, that solves the actual abort issue. And if I had a memory myself wouldn't have troubled you. Thank you for the patience.

I'm less sure if it helps with memory, as the structure of the program is invoking a new set of widgets that cache images, and it won't return to the event loop until those are all created and the first ones displayed.

Though, to be fair, I'm still struggling to see how much memory any of this is really using, I think I need to spend some time on that issue before working too hard to fix a problem that might not be significant. What I did (while waiting for this solution) was do a setRowCount(0) on the QTableWidget, and hope that gave back memory, instead of deleting it.

Are there any good dynamic analysis tools that can instrument QT-specific programs to provide a view at runtime (during development) of object usage, object size, leaks, etc.? I know of some C++ tools for memory leaks of course, but wondered if there is anything more QT specific, that might also do things like indicate widget ownership nesting (or un-owned), sizing, visibility, etc? Or build-time options for QT itself (I am building QT from source) that adds some instrumentation.

I ask because about half the time when I spend a lot of time doing something manually I find there's an object or method already there I just missed. :rolleyes:

So your signature line, Santosh, is very apt.

anda_skoa
11th March 2017, 10:54
Usually the C++ tools are very applicable as the Qt specific things are similar to situations with a shared pointer.

But you could check if GammaRay (https://www.kdab.com/development-resources/qt-tools/gammaray/) has a plugin for that as it knows and tracks an application's QObject instances.
If it does not it might not be too difficult to write on.

Cheers,
_