Ali Tavakol
Ali Tavakol

Reputation: 439

Load huge text buffer into QPlainTextEdit

What is the correct and optimum way to show a huge text buffer in a QPlainTextEdit widget? I mean listen to scrollbar move events, and dynamically pass only the visible portion of the text to the widget, according to current scrollbar position.

I cannot send the entire buffer to the widget using setPlainText because the text buffer is more than 1 GB in size, and that function takes a copy of it, which doubles memory usage.

Upvotes: 1

Views: 1280

Answers (1)

Fareanor
Fareanor

Reputation: 6805

Assuming you have a 1GB data and you don't want to exceed this memory load, I think you should read you data part by part and append them to the QPlainTextEdit's buffer. This way, you'll never exceed your 1GB memory usage for your huge text.
Indeed, the temporary variable used to store the loaded part will be erased at each iteration and you just have to destroyed it at the end of your loop.

Moreover, if you want only the visible part to be colored in a different way (as you said in our discussion), I think you should color the whole text because only the visible part color will be displayed (as the other parts are hidden, their color does not matter).
And when you will scroll down or up, the text being already coloured as you wish, you will have no action to perform.
Consequently, you will have the desired behaviour reducing the computation overhead at the same time because you don't perform color changing tasks at each scroll event.

Here is a minimal, complete and reproducible example of what I mean:

#include <QApplication>
#include <QFile>
#include <QTextEdit>
#include <QDebug>

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    QFile data_file("path/to/data/file/some_data.txt");
    if(!data_file.open(QIODevice::ReadOnly | QIODevice::Text))
        return -1;

    // ---------- ---------- ---------- ---------- ----------
    // Set the text color
    QTextEdit view;
    view.setTextColor(Qt::darkGreen);

    // read 100 chars by 100 chars (set the value you want)
    unsigned int MAX_LEN(100);

    // Create the temporary buffer
    char * part = new char[MAX_LEN];
    // Read the file part by part
    qint64 readBytes;
    while((readBytes = data_file.read(part, MAX_LEN)) > 0)
    {
        view.insertPlainText(QString(part).left(static_cast<int>(readBytes)));
    }

    // destroy the temporary buffer
    delete[] part;
    // ---------- ---------- ---------- ---------- ----------

    data_file.close();

    view.show();

    return app.exec();
}

EDIT:

If loading the full data in the QPlainTextEdit slows down you GUI too much, I think you can load the data as you did and just set a part of the data in the QPlainTextEdit. And on scroll event, you can use QPlainTextEdit::textCursor() combined with QTextCursor::atStart() and QTextCusrsor::atEnd() to detect if the user has reached the beginning or the end of the displayed part. For example, if the user has reached the end, you get the cursor position, and you use it to set the following part instead of the current one (perhaps using an overlapping section in order to make the trick smoother).

Upvotes: 1

Related Questions