I'm trying to display a dynamically updating table using QTimer
with a refresh rate of 1s. I'm calling the function create_table
which in turn calles create_title
. The code runs without complaints but tracking memory usage one finds that it keeps creeping up steadily till the program becomes unresponsive, or crashes.
void MainWindow::TableDisplay(QWidget *tab) {
auto timer = new QTimer(this);
connect(timer, &QTimer::timeout, [refreshed_table_data, tab, this]() {
auto tableView = create_table(tab, refreshed_table_data, "My table");
});
timer->start(1000);
}
The culprits seem to be the various new
statements (indicated by comments in my code) which seem to create a fresh zombies/leak every time QTimer
runs a loop.
auto create_title(const std::string &title, QWidget * widget) {
auto tableTitle = new QLabel(title.c_str(), widget); // <-- new
tableTitle->setAlignment(Qt::AlignLeft);
tableTitle->show();
}
auto create_table(QWidget * tab,
const std::vector<std::string> &v,
const std::string &title) {
auto tableView = new QTableView(tab); // <-- new
auto model = new MyModel(v, tab); // <-- new
tableView->setModel(model);
tableView->setStyle(new QProxyStyle(QStyleFactory::create("Fusion"))); // <-- new
tableView->setHorizontalHeader(new QHeaderView(Qt::Horizontal)); // <-- new
create_title(title, tab);
tableView->show();
return tableView;
}
One solution could be to have the pointers initalized by new
defined as member variables of MainWindow
so that they are defined only once. But if I'm calling several such timed-functions, it would quickly become cumbersome, even more so when one considers there are rendering elements such as the line new QProxyStyle(QStyleFactory::create("Fusion"))
etc which would then need to be accorded the status of member variables.
I tried wrapping the new
statements with QScopePointer
s but unfortunately the instances get destroyed right after create_table
goes out its scope, resulting in no rendering of the table graphics.
What's the right way of writing create_table
without creating zombies?
CodePudding user response:
For the question itself: Your createTable
method could call QTimer::singleShot
to schedule an update one second later.
auto create_table(QWidget * tab,
const std::vector<std::string> &v,
const std::string &title) {
...
QTimer::singleShot(1000 /*ms*/, this /*context*/, [this, tab, v, title]() {
create_table(tab, v, title);
});
return tableView;
}
However, as Igor noted, this whole approach seems backwards. The model should update itself, preferably event-based but if it has to poll external resources, it may have to use a timer itself.
Setting an entirely new model for a view is very expensive (because the view has to create everything from scratch) and can have annoying side-effects on the GUI side.