Markdown编辑器大家应该都知道,很受程序员喜欢。许多人都在创建一个Markdown编辑器,有些很有创意,有些则很无聊。
在我们开始之前,来解释一下为什么人们不想用tkinter来构建Markdown编辑器。这是因为没有默认的简单方法来显示markdown输入的html数据。甚至没有一个默认的tkinter组件来显示html数据。您可以简单地编写/编辑markdown,但是没有简单的方法在应用程序中显示输出。
但是,现在有了tk_html_widgets,它可以帮助我们显示html输出。
但它当然也有一些问题:字体太小,不支持附加远程照片。
现在让我们能开始构建吧。
开始构建:
首先,请确保您已安装Python 3和Tkinter。 如果没有,您可以从这里下载:
python.org/downloads(Tkinter已包含Python中)。
我们需要的其他东西是tkhtmlview和markdown2。 您可以通过运行pip install tkhtmlview markdown2或pip3 install tkhtmlview markdown2来安装它们(如果您有多个Python版本)。
我们将从导入必要的库开始。
from tkinter import *
from tkinter import font , filedialog
from markdown2 import Markdown
from tkhtmlview import HTMLLabel
在第一行中,我们从tkinter包中导入(几乎)所有内容。
在第二行中,我们导入字体和文件对话框。 需要使用font来设置输入字段的样式(例如Font,Font Size),并导入filedialog以打开markdown文件以进行编辑(和/或保存我们的markdown文件)。
在第三行中,导入了Markdown,以帮助我们将Markdown源转换为html,并使用HTMLLabel(在第四行中导入)将其显示在输出字段中。
之后,我们将创建一个名为Window的框架类,该框架类将从tkinters的Frame类继承。 它将保存我们的输入和输出字段。
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.myfont = font.Font(family="Helvetica", size=14)
self.init_window()
在此代码块中,我们首先定义一个称为Window的类,该类继承tkinter的Frame小部件类。
现在,在初始化函数中,我们将master作为参数,用作框架的父级。在下一行中,我们初始化一个Frame。
接下来,我们声明一个名为self.myfont的自定义字体对象,其字体家族为Helvetica(您可以选择任何字体家族),大小为15,将在我们的markdown输入字段中使用。
最后,我们调用init_window函数,将我们的应用程序置于核心位置。
我们将fill关键字参数设置为BOTH,这实际上是从tkinter库导入的。它告诉框架在水平和垂直方向上都填充窗口,并且expand关键字参数设置为1(表示True),这告诉我们框架是可扩展的。简而言之,无论我们如何拉伸窗口大小或最大化窗口大小,框架都将填充窗口。
为了解决这个问题,我们将以下代码放在脚本的末尾:
root = Tk()
root.geometry("800x600")
app = Window(root)
app.mainloop()
接下来,将窗口的几何形状设置为800x600的长方体,800是窗口的高度,600是窗口的宽度。 在下一行中,您可以看到我们正在创建一个Window对象。 我们将root变量推入框架的root,并将其存储在名为app的变量中。
接下来要做的就是调用mainloop函数,该函数告诉我们的应用程序运行!

但这只是一个空白窗口。 要在窗口中写入内容,我们需要添加一个文本字段,在其中写入我们的markdown。 为此,我们将使用tkinter中的Text小部件。
self.inputeditor = Text(self, width="1")
self.inputeditor.pack(fill=BOTH, expand=1, side=LEFT)
不要与...混淆(三个点),我把它们放在那里只是为了表示在此代码块之前有多行代码。
在这里,我们创建了一个宽度为1的Text小部件。不要误会,以为错了-这里的大小是使用比例来完成的。 当我们将其放入输出框中时,您将在接下来的几秒钟内更清楚地了解它。
然后,我们将其包装到框架中,并使其在水平和垂直方向上均可拉伸。
运行脚本时,您会看到“Multiline Input Field”已接管了整个“窗口”。 如果您开始写它,您可能会注意到字符太小了。

我已经知道会出现这个问题。 这就是为什么我之前告诉过您创建自定义字体对象(self.myfont)的原因。 现在,如果您执行以下操作:
self.inputeditor = Text(self, width="1" , font=self.myfont)
(这里,我们告诉Text小部件使用自定义字体,而不是默认的小字体!)
...输入字段的字体大小将增加到15。运行脚本以检查是否一切正常。

现在,我认为是时候添加outputbox了,我们在编写时将看到markdown源代码的html输出。
为此,我们要添加一个HTMLLabel,在init_window函数中是这样的:
我们使用tkhtmlview中的HTMLLabel,宽度仍旧为1。 我们将宽度设置为1,因为窗口将在输入字段和输出框之间以1:1的比例共享(运行脚本时您会明白我的意思)。
html关键字参数存储将在第一次显示的值。
然后,将其打包在窗口中,将side作为RIGHT置于输入字段的右侧。fit_height()使文本适合小部件。
现在运行代码,如下所示:
现在,如果您开始在输入字段中书写,输入时输出不会得到更新。 那是因为我们还没有告诉我们的程序这样做。
为此,我们首先要与编辑器绑定一个事件。 然后,你进行修改文本,输出都会得到更新,如下所示:
self.inputeditor.bind("<<Modified>>", self.onInputChange)
将这一行放到init_window()函数中。
这一行告诉inputeditor在文本改变时调用onInputChange函数。但是因为我们还没有那个函数,我们需要把它写出来。
...
def onInputChange(self , event):
self.inputeditor.edit_modified(0)
md2html = Markdown()