Best strategy to update QTableView with data in real-time from different threads
Asked Answered
C

2

7

I have application that for now starting few threads ( like 5 – 10 ) to collect data from different source .
They are separated from the main GUI thread so I don’t feel any slowness in the GUI and I can keep working while the background threads are working . all great .
But now I like to be able to display the results in QTableView in my main GUI . the data is strings allots of them and it can have between 10,000 to 100,000 results that supposed to be upto 100,000 rows in the QTableView.

My question is what is the best way to update the Table in the Main GUI from the threads so TH GUI won’t be slow or idle while updating.

Coben answered 28/11, 2012 at 12:31 Comment(1)
Round-robin insert, from worker threads, in the order required.Sylphid
G
9

This is how I would do it:

Add a signal to the worker threads that is emitted each time a new batch of data is ready. Connect this signal to a slot defined in the main GUI thread using Qt::QueuedConnection. This slot should collect the processed data from the worker threads and insert it into the table's model. Model should be naturally also in the GUI thread.

Update 1

More detailed explanation. You already got the threads down so all you'll have to do is to expand them a little. Example:

// NOTE:
// In this example I'm assuming that the thread continues to work after
// preparing first batch of data. One thread can prepare multiple batches
// over time. If that's not the case for you then you can probably
// safely ignore mutex stuff and intermediary tmp variables.
class MyWorker : public QThread
{
    // ...
    public:
        void run()
        {
            while (bWork)
            {
                QList<MyData> myData;
                // Populate 'myData' variable with your data.
                // ...

                // Now, store myData in more persistent buffer and emit the
                // ready signal.
                dataBatchMutex.lock();
                dataBatch.append(myData);
                dataBatchMutex.unlock();
                emit dataBatchReady();
            }
        }

        QList<MyData> popLastBatch()
        {
            QMutexLocker l(&dataBatchMutex);
            QList<MyData> tmp = dataBatch;
            dataBatch.clear();
            return tmp;
        }

    signals:
        void dataBatchReady();

    private:
        QMutex dataBatchMutex;
        QList<MyData> dataBatch;
};

We have the worker thread. Now about the GUI thread:

  1. Create your worker threads objects.
  2. Connect the dataBatchReady() signal to a slot in the GUI thread. Remember to use Qt::QueuedConnection.
  3. Start the threads.
  4. When that slot is executed you need to figure out which worker thread has the new data. You may pop them all (not very efficient) or you may add additional method to the worker to find out if the dataBatch field is not empty. You may also invent other way to figure out which thread emitted the signal - that's up to you to figure out.
  5. When you figure out the thread just call the popLastBatch() on that thread and add the returned list to the model. The model will take care of the rest. If you still have performance issues then refer to tHand's response.

Note: I didn't test the code so it may contain some obvious errors. You should get the idea, though.

Gigi answered 28/11, 2012 at 12:59 Comment(8)
can it slow things down , if i have like i said 100,000 rows needs to update and im getting like 10 - 20 rows each secoundCoben
Depends by what you mean by "slowing things down". Will it add some artificial delays? I doubt it. Will it cause freezes in your program? Rather not. If you're getting 10 - 20 rows per second then, given that the thing is programmed correctly, 10 - 20 new rows will appear in the table each second. That's actually how correctly programmed server browsers for games work.Gigi
well this is the question , how to program it right , in Qt you have many ways , but what is the best in this caseCoben
I've added "Update 1" section to my answer.Gigi
thanks for the anwser how do i send databatch list to the model?Coben
1. doc.qt.digia.com/4.7/model-view-programming.html 2. doc.qt.digia.com/4.7/qstandarditemmodel.html 3. doc.qt.digia.com/4.7/qstringlistmodel.htmlGigi
Thanks for the links but i know them well ( i think ... ) i just ask in other words how to make it thread safe when i pass the data to the main GUI. i can emit signal to the main GUI with the data but is it thread safe to do it all the time ?Coben
As long as you stick to the QueuedConnection it will be safe.Gigi
D
1

Your performance problem may be related to actions performed by the control as each row is added.

For example see: QTableView is extremely slow (even for only 3000 rows)

Diogenes answered 28/11, 2012 at 13:32 Comment(2)
good link , with good tips , but my problem is bit different . for sure i need to make custom model to control when and how to insert the data , the question is what is the best strategy when im getting the data in real-time from threadsCoben
Point taken. I think ZalewaPL has the right idea above, funnel the data back into the UI with a thread managing a queue.Diogenes

© 2022 - 2024 — McMap. All rights reserved.