【问题标题】:Render Markdown with PyQt5使用 PyQt5 渲染 Markdown
【发布时间】:2021-05-09 23:06:34
【问题描述】:

如何在我的 PyQt5 应用程序中呈现 markdown 文件?

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

在评论中,有人引用了this 示例。然而,它是一个完整的 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_()

【问题讨论】:

  • Qt 从 5.14 开始提供对 Markdown 的支持。使用setMarkdown()
  • 我没有找到QWebEngineView::setMarkDown()。您使用的是什么文档?也许看看第一个提供的链接,以便您了解我的问题。我不仅为本地文件寻找解决方案,还为外部文件寻找解决方案。
  • 对不起,我指的是 QTextEdit 并错过了第一个链接(顺便说一句,它可以加载外部源,但它有点棘手,需要 QNetworkAccessManager)。也许您可以使用QTextDocument.setMarkDown(),然后使用QTextDocument.toHtml(),然后为Web 视图设置该html,假设img 资源地址保持不变。否则,您将需要使用允许 Markdown 解析的外部模块。

标签: python pyqt pyqt5 qwebengineview


【解决方案1】:

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

import os.path
import sys

from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTextCodec, QUrl
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWidgets import QApplication

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


class Document(QObject):
    textChanged = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.m_text = ""

    def get_text(self):
        return self.m_text

    def set_text(self, text):
        if self.m_text == text:
            return
        self.m_text = text
        self.textChanged.emit(self.m_text)

    text = pyqtProperty(str, fget=get_text, fset=set_text, notify=textChanged)


class DownloadManager(QObject):
    finished = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)

        self._manager = QNetworkAccessManager()
        self.manager.finished.connect(self.handle_finished)

    @property
    def manager(self):
        return self._manager

    def start_download(self, url):
        self.manager.get(QNetworkRequest(url))

    def handle_finished(self, reply):
        if reply.error() != QNetworkReply.NoError:
            print("error: ", reply.errorString())
            return
        codec = QTextCodec.codecForName("UTF-8")
        raw_data = codec.toUnicode(reply.readAll())
        self.finished.emit(raw_data)


def main():

    app = QApplication(sys.argv)

    filename = os.path.join(CURRENT_DIR, "index.html")

    document = Document()
    download_manager = DownloadManager()

    channel = QWebChannel()
    channel.registerObject("content", document)

    # remote file
    markdown_url = QUrl.fromUserInput(
        "https://raw.githubusercontent.com/eyllanesc/stackoverflow/master/README.md"
    )
    # local file
    # markdown_url = QUrl.fromUserInput(/path/of/markdown.md)

    download_manager.finished.connect(document.set_text)
    download_manager.start_download(markdown_url)

    view = QWebEngineView()
    view.page().setWebChannel(channel)
    url = QUrl.fromLocalFile(filename)
    view.load(url)
    view.resize(640, 480)
    view.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

index.html

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<head>
  <link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">
  <script src="3rdparty/marked.js"></script>
  <script src="qrc:/qtwebchannel/qwebchannel.js"></script>
</head>
<body>
  <div id="placeholder"></div>
  <script>
  'use strict';

  var placeholder = document.getElementById('placeholder');

  var updateText = function(text) {
      placeholder.innerHTML = marked(text);
  }

  new QWebChannel(qt.webChannelTransport,
    function(channel) {
      var content = channel.objects.content;
      updateText(content.text);
      content.textChanged.connect(updateText);
    }
  );
  </script>
</body>
</html>
├── 3rdparty
│   ├── markdown.css
│   ├── MARKDOWN-LICENSE.txt
│   ├── marked.js
│   ├── MARKED-LICENSE.txt
│   └── qt_attribution.json
├── index.html
└── main.py

注意: 3rdparty 文件夹中的文件在the official Qt repository.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 2021-04-07
    相关资源
    最近更新 更多