如何在 tkinter 中显示 Markdown 格式文本?

问题描述 投票:0回答:2

python-3.x
tkinter
GUI 中,我开发了一个带有常规简单窗口的程序。

我想在程序窗口上显示保存在名为 markdownText 的字符串中的

markdown
格式字符串:

markdownText='_italic_ or **bold**'

期望的输出是:

斜体粗体

有什么解决办法吗?

python-3.x tkinter markdown
2个回答
11
投票

我只是在寻找类似的解决方案,而且确实似乎没有一个用于Python、TkInter和markdown组合的默认模块/类/库。然而,继续搜索发现了以下选项:

  • Python-Markdown – 这个模块能够将 Markdown 解析为以下输出格式:Python-Markdown 可以输出 HTML4、XHTML 和 HTML5 格式的文档。
  • TkInter 显示 html – 正如链接的答案所示,Tkhtml 可以“很好地”显示 html,并且它有一个 python 包装器

换句话说,如果您愿意使用转换为 html 的中间步骤,这可能是您在 tkinter GUI 中显示 Markdown 字符串的可行途径。


0
投票

如果你不想要holroy的伟大建议转换为html并显示它,而只想要markdown进行基本格式化,你可以编写一个基本的markdown解析器。

但是,如果您想要完整的 Markdown 支持,请使用真正的解析器,如 markopython-markdown 并弄清楚如何遍历文档以将每个项目添加到

tk.Text

否则,看看:

import re
import tkinter as tk
import tkinter.font as tkFont


class SimpleMarkdownText(tk.Text):
    """
    Really basic Markdown display. Thanks to Bryan Oakley's RichText:
    https://stackoverflow.com/a/63105641/79125
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        default_font = tkFont.nametofont(self.cget("font"))

        em = default_font.measure("m")
        default_size = default_font.cget("size")
        bold_font = tkFont.Font(**default_font.configure())
        italic_font = tkFont.Font(**default_font.configure())

        bold_font.configure(weight="bold")
        italic_font.configure(slant="italic")

        # Small subset of markdown. Just enough to make text look nice.
        self.tag_configure("**", font=bold_font)
        self.tag_configure("*", font=italic_font)
        self.tag_configure("_", font=italic_font)
        self.tag_chars = "*_"
        self.tag_char_re = re.compile(r"[*_]")

        max_heading = 3
        for i in range(1, max_heading + 1):
            header_font = tkFont.Font(**default_font.configure())
            header_font.configure(size=int(default_size * i + 3), weight="bold")
            self.tag_configure(
                "#" * (max_heading - i), font=header_font, spacing3=default_size
            )

        lmargin2 = em + default_font.measure("\u2022 ")
        self.tag_configure("bullet", lmargin1=em, lmargin2=lmargin2)
        lmargin2 = em + default_font.measure("1. ")
        self.tag_configure("numbered", lmargin1=em, lmargin2=lmargin2)

        self.numbered_index = 1

    def insert_bullet(self, position, text):
        self.insert(position, f"\u2022 {text}", "bullet")

    def insert_numbered(self, position, text):
        self.insert(position, f"{self.numbered_index}. {text}", "numbered")
        self.numbered_index += 1

    def insert_markdown(self, mkd_text):
        """A very basic markdown parser.

        Helpful to easily set formatted text in tk. If you want actual markdown
        support then use a real parser.
        """
        for line in mkd_text.split("\n"):
            if line == "":
                # Blank lines reset numbering
                self.numbered_index = 1
                self.insert("end", line)

            elif line.startswith("#"):
                tag = re.match(r"(#+) (.*)", line)
                line = tag.group(2)
                self.insert("end", line, tag.group(1))

            elif line.startswith("* "):
                line = line[2:]
                self.insert_bullet("end", line)

            elif line.startswith("1. "):
                line = line[2:]
                self.insert_numbered("end", line)

            elif not self.tag_char_re.search(line):
                self.insert("end", line)

            else:
                tag = None
                accumulated = []
                skip_next = False
                for i, c in enumerate(line):
                    if skip_next:
                        skip_next = False
                        continue
                    if c in self.tag_chars and (not tag or c == tag[0]):
                        if tag:
                            self.insert("end", "".join(accumulated), tag)
                            accumulated = []
                            tag = None
                        else:
                            self.insert("end", "".join(accumulated))
                            accumulated = []
                            tag = c
                            next_i = i + 1
                            if len(line) > next_i and line[next_i] == tag:
                                tag = line[i : next_i + 1]
                                skip_next = True

                    else:
                        accumulated.append(c)
                self.insert("end", "".join(accumulated), tag)

            self.insert("end", "\n")


def run_rich_edit():
    root = tk.Tk()

    default_font = tkFont.nametofont("TkDefaultFont")
    default_font.configure(size=12)

    text = SimpleMarkdownText(root, width=45, height=22, font=default_font)
    text.pack(fill="both", expand=True)

    text.insert_markdown(
        """
# Rich Text Example
Hello, world
This line **has bold** text.
This line _has italicized_ text. Also *italics* using asterisks.
Text _with italics **and bold** does_ not work.

## Sub Heading
This is a more interesting line with _some_ italics, but also **some bold text**.
* Create a list
* With bullets
1. Create a list
1. Or numbers

1. Use blank lines
1. to restart numbering
"""
    )

    root.mainloop()


if __name__ == "__main__":
    run_rich_edit()

您可以看到有很多限制:没有斜体+粗体的组合,没有文字换行。但对于显示大块文本来说似乎要好得多。

© www.soinside.com 2019 - 2024. All rights reserved.