How to display HTML file in Qt application in realtime

John Reds

I'm developing an application with PySide2 and I need to display the content of an HTML file which is a sort of log file, so it is continuously changing. I need to see these changes in realtime on my application. Is there a smart and fast way to do so? Currently I'm continuously reading from the file and comparing last lines to see if there is a new line: if so I append it to the QTextEdit widget.

I thought that maybe Qt provides some functionalities to achieve this in a smarter way.

CODE SNIPPET

    path = some_file.html

    with open(path) as file:
        old = file.readlines()
        try:
            last_line = old[-1]
        except IndexError:
            last_line = ''
        while streaming:
            line = file.readline()
            if line and line != last_line:
                qtext_edit.append(line)
                last_line = line
John Reds

After some digging I came out with a solution that fits my needs.

As suggested in the comments, the best way could have been to exploit QFileSystemWatcher to trigger a signal every time the file is changed by using the fileChanged signal. The problem, in my case, is that the fileChanged signal is not triggered continuously as I expected (the file is being continuously written) and so the QTextEdit doesn't update as I expect.

Therefore the possible best solution has been discarded.

I decided to re-visit my old function and try to optimize it. Here's the code:

DATALOG_UPDATE_TIME = 0.1

class DatalogSignals(QObject):
    output = Signal(list)


class DatalogStreamer(QRunnable):
    def __init__(self, streaming: bool, datalog: str):
        super().__init__()
        self.streaming = streaming
        self.datalog = datalog
        self.signals = DatalogSignals()

    def run(self):
        with open(self.datalog) as file:
            file.readlines()
            while self.streaming:
                time.sleep(DATALOG_UPDATE_TIME)
                lines = file.readlines()
                if lines:
                    self.signals.output.emit(lines)
        LOG.debug('Datalog streaming finished')

    def stop(self):
        self.streaming = False

Note: the code I posted in the Question was in the run() function of QRunnable as well, but I didn't post it to make it easier to understand. Now I'm posting it integrally because I think that full code could be helpful to someone.

As you can notice, I exploited a feature of readlines(): after the first call, it starts to read from the last line it read. This means that if you called this function once, the second time you call readlines() (keeping the file opened) and the file didn't change, you'd get an empty list; whereas if the file changed, you would get a list with just the new lines and not all the file lines.

An object of the class DatalogStreamer is created in the main class and started in a QThreadPool (in order to not execute the code in the main thread and therefore not block the GUI). This is the method to start the streaming:

def _start_datalog_streaming(self):
    self.datalog_streamer = DatalogStreamer(not self.actionDisable.isChecked(), self.datalog_path)
    self.datalog_streamer.signals.output.connect(self.datalog_editor.update_datalog)
    self.thread_pool.start(self.datalog_streamer)

As you can see the output signal (the one that emits the new lines) is connected to method of the object datalog_editor (class DatalogEdit, which is nothing but a subclass of QTextEdit). Here's the method's implementation:

def update_datalog(self, lines):
    self.moveCursor(QTextCursor.End)
    for line in lines:
        self.insertHtml(line.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;") + "<br>")
    self.verticalScrollBar().setValue(self.verticalScrollBar().maximum())

I used insertHtml() because lines (list of strings) can contain html tags. Moreover, I replaced "\t" with 4 spaces (* ) as it was ignored and add a newline after every line (
*).

With this simple solution I have a solved three problems:

  • same subsequent lines were not printed (just the first) whereas now they all get printed
  • text in QTextEdit is now formatted as the one in the HTML file
  • the reading from file "sampling time" is increased from undefined (very small time) to 0.1s reducing computational effort

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related