使用 PyQt5 渲染 Markdown

Leg*_*tio 5 python pyqt pyqt5 qwebengineview

如何在 PyQt5 应用程序中渲染 Markdown 文件?

在这里我读到我应该使用 QWebEngineView 而不是 QTextEdit,因为 QTextEdit 无法渲染外部图像。

在评论中有人引用了这个例子。然而,它是一个完整的 Markdown 文本编辑器,并且另外用 C++ 编写。我尝试将所需的部分翻译成Python,但我不太明白它是如何工作的。我只需要一个最小的例子。

我现在拥有的是以下内容:

from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
import sys

app = QApplication(sys.argv)

web_widget = QWebEngineView()  
webChannel = QWebChannel()    # ?
page = QWebEnginePage()       # ?
web_widget.setPage(page)      # ? 
my_url = QUrl("/index.html")
web_widget.load(my_url)

# now somehow replace the placeholder in the loaded html page with file contents?

file_url = QUrl("file.md")

# help 


web_widget.show()
app.exec_()
Run Code Online (Sandbox Code Playgroud)

eyl*_*esc 10

自 Qt 5.14 起,QTextEdit 可以渲染 markdown,但正如 OP 指出的那样,它有一个限制:它无法渲染远程图像。因此,另一种方法是使用 QWebEngineView + js 库,如 markdown.js 和 Marked.js,如官方示例所示。您还可以使用 QNetworkAccessManager 下载远程 .md 文件。

\n
import os.path\nimport sys\n\nfrom PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTextCodec, QUrl\nfrom PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest\nfrom PyQt5.QtWebChannel import QWebChannel\nfrom PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage\nfrom PyQt5.QtWidgets import QApplication\n\nCURRENT_DIR = os.path.dirname(os.path.realpath(__file__))\n\n\nclass Document(QObject):\n    textChanged = pyqtSignal(str)\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.m_text = ""\n\n    def get_text(self):\n        return self.m_text\n\n    def set_text(self, text):\n        if self.m_text == text:\n            return\n        self.m_text = text\n        self.textChanged.emit(self.m_text)\n\n    text = pyqtProperty(str, fget=get_text, fset=set_text, notify=textChanged)\n\n\nclass DownloadManager(QObject):\n    finished = pyqtSignal(str)\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        self._manager = QNetworkAccessManager()\n        self.manager.finished.connect(self.handle_finished)\n\n    @property\n    def manager(self):\n        return self._manager\n\n    def start_download(self, url):\n        self.manager.get(QNetworkRequest(url))\n\n    def handle_finished(self, reply):\n        if reply.error() != QNetworkReply.NoError:\n            print("error: ", reply.errorString())\n            return\n        codec = QTextCodec.codecForName("UTF-8")\n        raw_data = codec.toUnicode(reply.readAll())\n        self.finished.emit(raw_data)\n\n\ndef main():\n\n    app = QApplication(sys.argv)\n\n    filename = os.path.join(CURRENT_DIR, "index.html")\n\n    document = Document()\n    download_manager = DownloadManager()\n\n    channel = QWebChannel()\n    channel.registerObject("content", document)\n\n    # remote file\n    markdown_url = QUrl.fromUserInput(\n        "https://raw.githubusercontent.com/eyllanesc/stackoverflow/master/README.md"\n    )\n    # local file\n    # markdown_url = QUrl.fromUserInput(/path/of/markdown.md)\n\n    download_manager.finished.connect(document.set_text)\n    download_manager.start_download(markdown_url)\n\n    view = QWebEngineView()\n    view.page().setWebChannel(channel)\n    url = QUrl.fromLocalFile(filename)\n    view.load(url)\n    view.resize(640, 480)\n    view.show()\n    sys.exit(app.exec_())\n\n\nif __name__ == "__main__":\n    main()\n
Run Code Online (Sandbox Code Playgroud)\n

索引.html

\n
<!doctype html>\n<html lang="en">\n<meta charset="utf-8">\n<head>\n  <link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">\n  <script src="3rdparty/marked.js"></script>\n  <script src="qrc:/qtwebchannel/qwebchannel.js"></script>\n</head>\n<body>\n  <div id="placeholder"></div>\n  <script>\n  \'use strict\';\n\n  var placeholder = document.getElementById(\'placeholder\');\n\n  var updateText = function(text) {\n      placeholder.innerHTML = marked(text);\n  }\n\n  new QWebChannel(qt.webChannelTransport,\n    function(channel) {\n      var content = channel.objects.content;\n      updateText(content.text);\n      content.textChanged.connect(updateText);\n    }\n  );\n  </script>\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 3rdparty\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 markdown.css\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 MARKDOWN-LICENSE.txt\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 marked.js\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 MARKED-LICENSE.txt\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 qt_attribution.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.html\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 main.py\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

注意: 3rdparty文件夹中的文件位于官方Qt存储库中。

\n