如何在Qt应用程序中实时显示HTML个文件

How to display HTML file in Qt application in realtime

我正在使用 PySide2 开发应用程序,我需要显示 HTML 文件的内容,该文件是一种日志文件,因此它会不断变化。我需要在我的应用程序中实时查看这些更改。 有没有一种聪明而快速的方法来做到这一点?目前我正在不断地从文件中读取并比较最后几行以查看是否有新行:如果是这样我将其附加到 QTextEdit 小部件。

我想也许 Qt 提供了一些功能来以更智能的方式实现这一点。

代码片段

    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

经过一番挖掘,我得出了一个适合我需要的解决方案。

正如评论中所建议的,最好的方法可能是利用 QFileSystemWatcher 在每次使用 fileChanged 信号更改文件时触发信号。就我而言,问题是 fileChanged 信号没有像我预期的那样连续触发(文件正在连续写入),因此 QTextEdit 没有像我预期的那样更新。

因此可能的最佳解决方案已被舍弃。

我决定重新访问我的旧功能并尝试对其进行优化。 这是代码:

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

注意:我在问题中post编辑的代码在QRunnablerun()函数中作为好吧,但我没有 post 它是为了让它更容易理解。现在我正在 post 整合它,因为我认为完整的代码可能对某人有帮助。

如您所见,我利用了 readlines() 的一个特性:在第一次调用后,它从它读取的 最后一行 开始读取。这意味着如果你调用这个函数一次,第二次调用 readlines() (保持文件打开)并且文件没有改变,你会得到一个空列表;而如果文件发生更改,您将获得一个仅包含新行而不是所有文件行的列表。

classDatalogStreamer的一个对象在主class中创建并在QThreadPool中启动(为了不在主线程中执行代码因此不会阻止 GUI)。这是启动流媒体的方法:

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)

如您所见,output 信号(发出新行的信号)连接到对象 datalog_editor 的方法(class DatalogEdit,它只不过是 QTextEdit 的子 class)。 这是该方法的实现:

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())

我使用 insertHtml() 因为 (字符串列表)可以包含 html 标签。此外,我用 4 个空格 (* ) 替换了“\t”,因为它被忽略了,并在每一行之后添加了一个换行符 (
*).

通过这个简单的解决方案,我解决了三个问题:

  • 没有打印相同的后续行(只是第一行),而现在它们都被打印了
  • QTextEdit 中的文本现在被格式化为 HTML 文件中的文本
  • 从文件读取“采样时间”从 未定义(非常小的时间)增加到 0.1 秒,减少了计算量