qtqt5readlineqtexteditqtextstream

Qt : Read a text file line by line in a specific time interval


I am trying to transfer the content of a text file to be displayed to the textEdit widget inside my GUI.

How can I make it display at the text edit one line at a time, instead of displaying all the content of the text file into the textEdit widget at one time?

By using "readLine" it can only display the first line of the text file content. How can I make it display the second line of the content after, let say 2 second?

Here's the sample of my code:

void ReadTextFile::on_pushButton_4_clicked() 
QFile textfile("my_file_here"); 
if (textfile.open(QIODevice::ReadOnly)||QIODevice::Text) { 
QTextStream in(&textfile); 
while (!in.atEnd()) { 
QString line = in.readLine(); 
ui->textEdit->append(line); 
} 
textfile.close();
 qDebug() <<"Close Text File"; 
} 
qDebug() <<"Out Pushbutton File"; 
}

I am a new guy learning Qt Programming, so please be gentle to me~~ ^^


Solution

  • You can use a timer to trigger reading of successive lines. This functionality is best separated into its own class that emits a signal each time a new line is available:

    // https://github.com/KubaO/stackoverflown/tree/master/questions/timed-read-44319722
    #include <QtWidgets>
    
    class PeriodicReader : public QObject {
       Q_OBJECT
       QTimer m_timer{this};
       QFile m_file{this};
       void readLine() {
          if (m_file.atEnd()) {
             m_timer.stop();
             return;
          }
          emit newLine(m_file.readLine());
       }
    public:
       explicit PeriodicReader(QObject * parent = {}) : QObject(parent) {
          connect(&m_timer, &QTimer::timeout, this, &PeriodicReader::readLine);
       }
       void load(const QString & fileName) {
          m_file.close(); // allow re-opening of the file
          m_file.setFileName(fileName);
          if (m_file.open(QFile::ReadOnly | QFile::Text)) {
             readLine();
             m_timer.start(300); // 0.3s interval
          }
       }
       Q_SIGNAL void newLine(const QByteArray &);
    };
    

    Since we're using a QPlainTextEdit to display the text, we need to convert the raw lines into strings. We must remove any line endings since QPlainTextEdit::appendPlainText already adds a paragraph ending:

    QString lineToString(QByteArray line) {
       while (line.endsWith('\n') || line.endsWith('\r'))
          line.chop(1);
       return QString::fromUtf8(line);
    }
    

    It's now a simple matter to put it together into a demo:

    int main(int argc, char ** argv) {
       QApplication app{argc, argv};
    
       QWidget window;
       QVBoxLayout layout{&window};
       QPushButton load{"Load"};
       QPlainTextEdit edit;
       layout.addWidget(&load);
       layout.addWidget(&edit);
       window.show();
    
       PeriodicReader reader;
       QObject::connect(&load, &QPushButton::clicked, [&]{
          auto name = QFileDialog::getOpenFileName(&window);
          if (!name.isEmpty()) {
             edit.clear(); // allow re-opening of the file
             reader.load(name);
          }
       });
       QObject::connect(&reader, &PeriodicReader::newLine, &edit,
                        [&](const QByteArray & line){ edit.appendPlainText(lineToString(line)); });
    
       return app.exec();
    }
    #include "main.moc"
    

    This concludes the complete example.