PDA

View Full Version : Using QTableView to display an infinite incoming log stream.



XplosiveLugnut
12th October 2016, 02:26
Alrighty. As per the title, lets say I receive log messages every so often. In my test, the logs are just a QString time stamp in column 0 and a QString made from an unsigned 64 bit integer in column 1. Column 1's source is a count of the "logs".

My mainwindow.ui has a single tableView dropped in it.

Here are my three source files:

main.cpp


#include "mainwindow.h"

#include <QApplication>

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

return a.exec();
}

mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <thread>

#include <QMainWindow>
#include <QStandardItemModel>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

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

void loop();

private:
Ui::MainWindow *ui;

QStandardItemModel *generic_data_model_m;

void loop_priv();

std::thread *thread_m;

bool kill_thread;
};

#endif // MAINWINDOW_H

mainwindow.cpp


#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDateTime>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
kill_thread(false)
{
generic_data_model_m = new QStandardItemModel(150, 2, this);

generic_data_model_m->setHorizontalHeaderItem(0, new QStandardItem(QString("time")));
generic_data_model_m->setHorizontalHeaderItem(1, new QStandardItem(QString("num")));

ui->setupUi(this);
ui->tableView->setModel(generic_data_model_m);
generic_data_model_m->setRowCount(0);
}

MainWindow::~MainWindow()
{
delete ui;
kill_thread = true;
thread_m->join();
delete thread_m;
delete generic_data_model_m;
}

void MainWindow::loop()
{
thread_m = new std::thread(&MainWindow::loop_priv, this);
}

void MainWindow::loop_priv()
{
QList<QStandardItem *> items;
quint64 i = 0;

while(!kill_thread) {
if (generic_data_model_m->rowCount() > 100) {
std::this_thread::sleep_for(std::chrono::milliseco nds(100)); // arbitrary sleep to improve stability
generic_data_model_m->removeRows(0, 50);
std::this_thread::sleep_for(std::chrono::milliseco nds(100));
}
QList<QStandardItem *> items;
items = {new QStandardItem(QDateTime::currentDateTime().toStrin g()), new QStandardItem(QString::number(i))};
generic_data_model_m->appendRow(items);
++i;
}
}


This is unrealistically fast, but I feel it should still be stable under these conditions. This program is very volatile. Any manipulation of the tableView is likely to cause a crash.

What I'm simulating is a constant stream of log messages, from some source, being inserted into the item model. The intent is for old logs to be removed as new ones are added.

Should I approach this with a different method?

Thanks!

anda_skoa
12th October 2016, 10:42
Don't access UI resources from any thread other than the main thread.

So in your case don't call methods of the table view or the model from the secondary thread.

Also access to "kill_thread" is neither mutex protected nor is it an atomic.

Cheers,
_