How to efficiently display almost real-time text (logging) without freezing an ui?



  • Currently I'm using QPlainTextEdit with addPlainText but it doesn't work really well.
    For example if I have something like

    for (int i = 0; i < n; i++) {
        display i in textedit
    }
    

    For n < 1e5 it work ok. But for>1e5 it starts freezing the UI. I tried adding some sort of buffering to the logging widget: i.e. store incoming strings in a QQueue and each 250ms or so (using timer) display them all at once, but it didn't solve the problem. As well as just concatenating strings together instead of a queue.
    Also, I tried displaying only fixed amount of messages(about 50) per 200ms but that, although improved situation a bit, still didn't solve the issue completely.
    The problem appears to be in appendPlainText invocation which always freezes GUI for a bit.
    (btw, I tried replacing it with insertPlainText but didn't see much difference and doc didn't help to clear up what the difference is).



  • @flashmozzg The problem here is constantly updating the textedit without allowing the system to do anything else (because you're in the for loop).

    So basically, build up the data you want to display and update the text edit once, like so:

    QString myStr;
    for (auto i=0;i<n;++i)
    {
       myStr += myNewData;
    }
    
    textedit->setPlainText(myStr);
    

    If you need to constantly deliver updates then you should do it via a signal/slot type mechanism and not in a for loop like that. Any loop will hang a thread until it's done. So if you had to have the loop you would again build the data in a loop outside the GUI thread, and deliver the updates via a signal to your GUI thread that updates the textedit.

    Also if you make the data in a textedit huge it will not perform well. You may need to use a faster view to display it.


  • Lifetime Qt Champion

    Hi,

    To add to @ambershark, one alternative could be to use a QListView and a QStringListModel rather than a QTextEdit. That way you optimise things a bit more for displaying and scrolling.

    Hope it helps



  • @ambershark
    Sorry, I realize that my example was a bit misleading.
    The loop is happening in another (non-GUI) thread and it sends a signal to display some text (like text representation of i) in the QPlainTextEdit.

    Btw, I tried keeping a queue of incoming messages and then show them one by one, or just appending everything to one big string and then showing it, but I didn't really see much performance difference.

    Anyway, I was somewhat able to overcome this annoyance by finding the right values n and m for the number of msgs (n) in the queue processed every m milliseconds. That way at least it doesn't freeze the gui, though the backlog becomes massive.



  • @flashmozzg What kind of data is this? That seems like a lot of data to be sending to a GUI control. They really aren't designed for that level of updates.

    Like @SGaist said though you need to use a more optimized widget than a QTextEdit. You may even need to look into using QGraphicsView or something to utilize the graphics card for rendering on a component like that. However I would just do the view/model and control what the user actually sees. That should be nice and fast, especially compared to a QTextEdit which was never intended for the use you using it for.



  • @ambershark said in How to efficiently display almost real-time text (logging) without freezing an ui?:

    What kind of data is this? That seems like a lot of data to be sending to a GUI control. They really aren't designed for that level of updates.

    Just some logging from some interpretation/evaluation running in another thread.
    QPlainTexEdit seems to be barely enough with new added changes so I'll keep that for now, it's rather simple for what it's worth and I was able to push about 200 messages every 50 milliseconds, so it's OK.for now. The problem was that some pathological case like fast evaluation of while(true) {send signal to print something} would make application unresponsive and would require a restart, potentially losing some data. Now it's enough for the most common case.
    Though I'd still would like to know if there are some easy performance optimizations without switching to the whole new and different model.


  • Moderators

    @flashmozzg One optimization would be to buffer the log messages and when the buffer reaches some defined size then send it to the QPlainTextEdit. In other words: do not send each and every message but groups of messages. I don't think any human would recognize any difference at that speed.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.