自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Python構(gòu)建自己的Markdown編輯器

開(kāi)發(fā) 后端
不過(guò)很多開(kāi)發(fā)人員不希望使用Tkinter來(lái)構(gòu)建Markdown編輯器,如果您已經(jīng)熟悉Python和Tkinter,您可以輕松進(jìn)入本指南。

Markdown編輯器大家應(yīng)該都知道,很受程序員喜歡。許多人都在創(chuàng)建一個(gè)Markdown編輯器,有些很有創(chuàng)意,有些則很無(wú)聊。

不過(guò)很多開(kāi)發(fā)人員不希望使用Tkinter來(lái)構(gòu)建Markdown編輯器,如果您已經(jīng)熟悉Python和Tkinter,您可以輕松進(jìn)入本指南。

在我們開(kāi)始之前,來(lái)解釋一下為什么人們不想用tkinter來(lái)構(gòu)建Markdown編輯器。這是因?yàn)闆](méi)有默認(rèn)的簡(jiǎn)單方法來(lái)顯示markdown輸入的html數(shù)據(jù)。甚至沒(méi)有一個(gè)默認(rèn)的tkinter組件來(lái)顯示html數(shù)據(jù)。您可以簡(jiǎn)單地編寫/編輯markdown,但是沒(méi)有簡(jiǎn)單的方法在應(yīng)用程序中顯示輸出。

但是,現(xiàn)在有了tk_html_widgets,它可以幫助我們顯示html輸出。

現(xiàn)在讓我們能開(kāi)始構(gòu)建吧。

開(kāi)始構(gòu)建:

首先,請(qǐng)確保您已安裝Python 3和Tkinter。如果沒(méi)有,您可以從這里下載:

python.org/downloads(Tkinter已包含Python中)。

我們需要的其他東西是tkhtmlview和markdown2。您可以通過(guò)運(yùn)行pip install tkhtmlview markdown2或pip3 install tkhtmlview markdown2來(lái)安裝它們(如果您有多個(gè)Python版本)。

現(xiàn)在啟動(dòng)您喜歡的編輯器或IDE并創(chuàng)建一個(gè)新文件(例如www.linuxidc.com.py(我將其命名為linuxidc.com編輯器))。

我們將從導(dǎo)入必要的庫(kù)開(kāi)始。 

  1. from tkinter import *  
  2. from tkinter import font , filedialog  
  3. from markdown2 import Markdown  
  4. from tkhtmlview import HTMLLabel  

在第一行中,我們從tkinter包中導(dǎo)入(幾乎)所有內(nèi)容。

在第二行中,我們導(dǎo)入字體和文件對(duì)話框。需要使用font來(lái)設(shè)置輸入字段的樣式(例如Font,F(xiàn)ont Size),并導(dǎo)入filedialog以打開(kāi)markdown文件以進(jìn)行編輯(和/或保存我們的markdown文件)。

在第三行中,導(dǎo)入了Markdown,以幫助我們將Markdown源轉(zhuǎn)換為html,并使用HTMLLabel(在第四行中導(dǎo)入)將其顯示在輸出字段中。

之后,我們將創(chuàng)建一個(gè)名為Window的框架類,該框架類將從tkinters的Frame類繼承。它將保存我們的輸入和輸出字段。 

  1. class Window(Frame):  
  2.     def __init__(self, master=None):  
  3.         Frame.__init__(self, master)  
  4.         self.master = master  
  5.         self.myfont = font.Font(family="Helvetica"size=14 
  6.         self.init_window()  
  7.     def init_window(self):  
  8.         self.master.title("linuxidc.com編輯器")  
  9.         self.pack(fill=BOTHexpand=1 

在此代碼塊中,我們首先定義一個(gè)稱為Window的類,該類繼承tkinter的Frame小部件類。

現(xiàn)在,在初始化函數(shù)中,我們將master作為參數(shù),用作框架的父級(jí)。在下一行中,我們初始化一個(gè)Frame。

接下來(lái),我們聲明一個(gè)名為self.myfont的自定義字體對(duì)象,其字體家族為Helvetica(您可以選擇任何字體家族),大小為15,將在我們的markdown輸入字段中使用。

最后,我們調(diào)用init_window函數(shù),將我們的應(yīng)用程序置于核心位置。

在init_window函數(shù)中,我們首先將窗口的標(biāo)題設(shè)置為linuxidc.com編輯器。在下一行self.pack(fill=BOTH, expand=1)中,我們告訴Frame占用窗口的全部空間。

我們將fill關(guān)鍵字參數(shù)設(shè)置為BOTH,這實(shí)際上是從tkinter庫(kù)導(dǎo)入的。它告訴框架在水平和垂直方向上都填充窗口,并且expand關(guān)鍵字參數(shù)設(shè)置為1(表示True),這告訴我們框架是可擴(kuò)展的。簡(jiǎn)而言之,無(wú)論我們?nèi)绾卫齑翱诖笮』蜃畲蠡翱诖笮?,框架都將填充窗口?/p>

現(xiàn)在,如果您運(yùn)行www.linuxidc.com.py腳本,您將看不到任何內(nèi)容,因?yàn)槲覀儍H定義了該類,但從未調(diào)用過(guò)它。

為了解決這個(gè)問(wèn)題,我們將以下代碼放在腳本的末尾: 

  1. root = Tk()  
  2. root.geometry("800x600")  
  3. app = Window(root)  
  4. app.mainloop()  

接下來(lái),將窗口的幾何形狀設(shè)置為800x600的長(zhǎng)方體,800是窗口的高度,600是窗口的寬度。在下一行中,您可以看到我們正在創(chuàng)建一個(gè)Window對(duì)象。我們將root變量推入框架的root,并將其存儲(chǔ)在名為app的變量中。

接下來(lái)要做的就是調(diào)用mainloop函數(shù),該函數(shù)告訴我們的應(yīng)用程序運(yùn)行!

現(xiàn)在運(yùn)行www.linuxidc.com.py腳本。如果正確完成所有操作,您將看到一個(gè)空白窗口,如下所示:

但這只是一個(gè)空白窗口。要在窗口中寫入內(nèi)容,我們需要添加一個(gè)文本字段,在其中寫入我們的markdown。為此,我們將使用tkinter中的Text小部件。 

  1. ...  
  2. def init_window(self):  
  3.     self.master.title("linuxidc.com編輯器")  
  4.     self.pack(fill=BOTHexpand=1 
  5.     self.inputeditor = Text(self, width="1" 
  6.     self.inputeditor.pack(fill=BOTHexpand=1side=LEFT 

不要與...混淆(三個(gè)點(diǎn)),我把它們放在那里只是為了表示在此代碼塊之前有多行代碼。

在這里,我們創(chuàng)建了一個(gè)寬度為1的Text小部件。不要誤會(huì),以為錯(cuò)了-這里的大小是使用比例來(lái)完成的。當(dāng)我們將其放入輸出框中時(shí),您將在接下來(lái)的幾秒鐘內(nèi)更清楚地了解它。

然后,我們將其包裝到框架中,并使其在水平和垂直方向上均可拉伸。

運(yùn)行腳本時(shí),您會(huì)看到已接管了整個(gè)“窗口”。如果您開(kāi)始寫它,您可能會(huì)注意到字符太小了。

我已經(jīng)知道會(huì)出現(xiàn)這個(gè)問(wèn)題。這就是為什么我之前告訴過(guò)您創(chuàng)建自定義字體對(duì)象(self.myfont)的原因?,F(xiàn)在,如果您執(zhí)行以下操作: 

  1. self.inputeditor = Text(self, width="1" , font=self.myfont) 

(這里,我們告訴Text小部件使用自定義字體,而不是默認(rèn)的小字體!)

...輸入字段的字體大小將增加到15。運(yùn)行腳本以檢查是否一切正常。

現(xiàn)在,我認(rèn)為是時(shí)候添加outputbox了,我們?cè)诰帉憰r(shí)將看到markdown源代碼的html輸出。

為此,我們要添加一個(gè)HTMLLabel,在init_window函數(shù)中是這樣的: 

  1. self.outputbox = HTMLLabel(self, width="1"background="white"html="<h1>linuxidc.com</h1>" 
  2. self.outputbox.pack(fill=BOTHexpand=1side=RIGHT 
  3. self.outputbox.fit_height()  

我們使用tkhtmlview中的HTMLLabel,寬度仍舊為1。我們將寬度設(shè)置為1,因?yàn)榇翱趯⒃谳斎胱侄魏洼敵隹蛑g以1:1的比例共享(運(yùn)行腳本時(shí)您會(huì)明白我的意思)。

html關(guān)鍵字參數(shù)存儲(chǔ)將在第一次顯示的值。

然后,將其打包在窗口中,將side作為RIGHT置于輸入字段的右側(cè)。fit_height()使文本適合小部件。

現(xiàn)在運(yùn)行代碼,如下所示: 

現(xiàn)在,如果您開(kāi)始在輸入字段中書寫,輸入時(shí)輸出不會(huì)得到更新。那是因?yàn)槲覀冞€沒(méi)有告訴我們的程序這樣做。

為此,我們首先要與編輯器綁定一個(gè)事件。然后,你進(jìn)行修改文本,輸出都會(huì)得到更新,如下所示: 

  1. self.inputeditor.bind("<<Modified>>", self.onInputChange) 

將這一行放到init_window()函數(shù)中。

這一行告訴inputeditor在文本改變時(shí)調(diào)用onInputChange函數(shù)。但是因?yàn)槲覀冞€沒(méi)有那個(gè)函數(shù),我們需要把它寫出來(lái)。 

  1. ...  
  2. def onInputChange(self , event):  
  3.     self.inputeditor.edit_modified(0)  
  4.     md2html = Markdown()  
  5.     self.outputbox.set_html(md2html.convert(self.inputeditor.get("1.0" , END)))  

在第一行中,我們使用edit_modified(0)重置修改后的標(biāo)志,以便重用它。否則,在第一次事件調(diào)用之后,它將不再工作。

接下來(lái),我們創(chuàng)建一個(gè)名為md2html的Markdown對(duì)象。最后一行(上面標(biāo)紅那行),首先我們…等等!最后一行可能會(huì)讓一些讀者感到困惑。我把它分成三行。 

  1. markdownText = self.inputeditor.get("1.0" , END)  
  2. html = md2html.convert(markdownText) 
  3.  self.outputbox.set_html(html)  

在第一行中,我們從輸入字段的頂部到底部獲取markdown文本。第一個(gè)參數(shù),self.inputeditor.get,告訴它從第一行的第0個(gè)字符開(kāi)始掃描(1.0 => [LINE_NUMBER].[CHARACTER_NUMBER]),最后一個(gè)參數(shù)告訴它在到達(dá)末尾時(shí)停止掃描。

然后,我們使用md2html.convert()函數(shù)將掃描的markdown文本轉(zhuǎn)換為html,并將其存儲(chǔ)在html變量中。

最后,我們告訴outputbox使用.set_html()函數(shù)來(lái)顯示輸出!

運(yùn)行腳本。您將看到一個(gè)功能幾乎正常的markdown編輯器。當(dāng)您輸入輸入字段時(shí),輸出也將被更新。

但是…我們的工作還沒(méi)有完成。用戶至少需要能夠打開(kāi)和保存他們的文本。

為此,我們要在菜單欄中添加一個(gè)文件菜單。在這里,用戶可以打開(kāi)和保存文件,也可以退出應(yīng)用程序。

在init_window函數(shù)中,我們將添加以下行:

  1. self.mainmenu = Menu(self)  
  2. self.filemenu = Menu(self.mainmenu)  
  3. self.filemenu.add_command(label="打開(kāi)"command=self.openfile)  
  4. self.filemenu.add_command(label="另存為"command=self.savefile)  
  5. self.filemenu.add_separator()  
  6. self.filemenu.add_command(label="退出"command=self.quit)  
  7. self.mainmenu.add_cascade(label="文件"menu=self.filemenu)  
  8. self.master.config(menu=self.mainmenu)  

簡(jiǎn)單說(shuō)一下:

在這里,我們定義了一個(gè)新菜單,框架作為它的父菜單。

接下來(lái),我們定義另一個(gè)菜單和上一個(gè)菜單作為其父菜單。它將作為我們的文件菜單。

然后使用add_command()和add_separator()函數(shù)添加3個(gè)子菜單(打開(kāi)、另存為和退出)和分隔符。打開(kāi)子菜單將執(zhí)行openfile函數(shù),另存為子菜單將執(zhí)行savefile函數(shù)。最后,Exit將執(zhí)行一個(gè)內(nèi)建函數(shù)quit,該函數(shù)將關(guān)閉程序。

然后使用add_cascade()函數(shù)告訴第一個(gè)菜單對(duì)象包含filemenu變量。這包括標(biāo)簽文件中的所有子菜單。

最后,我們使用self.master.config()來(lái)告訴窗口使用主菜單作為窗口的菜單欄。

它看起來(lái)是這樣的,但是現(xiàn)在還不要運(yùn)行它。你會(huì)提示錯(cuò)誤,openfile和savefile函數(shù)沒(méi)有定義。

正如您現(xiàn)在看到的,我們必須在Window類中定義兩個(gè)函數(shù),我們將在其中使用tkinter的filedialog。

首先讓我們定義打開(kāi)文件的函數(shù):

  1. def openfile(self):  
  2.     openfilename = filedialog.askopenfilename(filetypes=(("Markdown File", "*.md , *.mdown , *.markdown"),  
  3.                                                                   ("Text File", "*.txt"),  
  4.                                                                   ("All Files", "*.*")))  
  5.     if openfilename:  
  6.         try:  
  7.             self.inputeditor.delete(1.0, END)  
  8.             self.inputeditor.insert(END , open(openfilename).read())  
  9.         except:  
  10.             print("無(wú)法打開(kāi)文件!")   

在這里,首先我們向用戶顯示一個(gè)文件瀏覽器對(duì)話框,允許他們使用filedialog.askopenfilename()選擇要打開(kāi)的文件。與filetypes關(guān)鍵字參數(shù),我們告訴對(duì)話框只打開(kāi)這些類型的文件通過(guò)傳遞一個(gè)元組與支持的文件(基本上所有類型的文件):

  •  帶 .md , .mdown , .markdown擴(kuò)展名的文件
  •  擴(kuò)展名為.txt的文本文件
  •  在使用通配符擴(kuò)展的下一行中,我們告訴對(duì)話框打開(kāi)任何擴(kuò)展名的文件。

然后我們檢查用戶是否選擇了一個(gè)文件。如果是,我們嘗試打開(kāi)文件。然后刪除輸入字段中從第一行的第0個(gè)字符到字段末尾的所有文本。

接下來(lái),我們打開(kāi)并讀取所選文件的內(nèi)容,并在輸入字段中插入內(nèi)容。

如果我們的程序不能打開(kāi)一個(gè)文件,它將打印出錯(cuò)誤。但是等等,這不是處理錯(cuò)誤的好方法。我們?cè)谶@里可以做的是向用戶顯示一個(gè)類似這樣的錯(cuò)誤消息:

為此,我們首先要從tkinter包中導(dǎo)入消息框messagebox。 

  1. from tkinter import messagebox as mbox 

然后,不像上面那樣只是打印一個(gè)錯(cuò)誤消息,我們將用下面的行替換那一行,以便向用戶顯示正確的錯(cuò)誤消息。

mbox.showerror(“打開(kāi)選定文件時(shí)出錯(cuò) " , "哎呀!,您選擇的文件:{}無(wú)法打開(kāi)!".format(openfilename))

這將創(chuàng)建一個(gè)錯(cuò)誤消息,就像我上面顯示的文件無(wú)法打開(kāi)時(shí)的屏幕截圖一樣。

mbox.showerror函數(shù),第一個(gè)參數(shù)是消息框的標(biāo)題。第二個(gè)是要顯示的消息。

現(xiàn)在,我們需要編寫一個(gè)savefile函數(shù)來(lái)保存markdown輸入。 

  1. def savefile(self):  
  2.         filedata = self.inputeditor.get("1.0" , END)  
  3.         savefilename = filedialog.asksaveasfilename(filetypes = (("Markdown File", "*.md"),  
  4.                                                                   ("Text File", "*.txt")) , title="保存 Markdown 文件" 
  5.         if savefilename:  
  6.             try:  
  7.                 f = open(savefilename , "w")  
  8.                 f.write(filedata)  
  9.             except:  
  10.                 mbox.showerror("保存文件錯(cuò)誤" , "哎呀!, 文件: {} 保存錯(cuò)誤!".format(savefilename))  

在這里,首先我們掃描輸入字段的所有內(nèi)容并將其存儲(chǔ)在一個(gè)變量中。然后,我們通過(guò)為兩種類型的文件類型(.md和.txt)。

如果用戶選擇一個(gè)文件名,我們將嘗試保存存儲(chǔ)在變量filedata中的輸入字段的內(nèi)容。如果發(fā)生異常,我們將向用戶顯示一條錯(cuò)誤消息,說(shuō)明程序無(wú)法保存文件。

不要忘記測(cè)試您的應(yīng)用程序以檢查任何bug !如果你的程序沒(méi)有錯(cuò)誤,運(yùn)行完美應(yīng)該是這樣的:

OK,本文就這樣,你學(xué)會(huì)了嗎? 

 

責(zé)任編輯:龐桂玉 來(lái)源: Linux公社
相關(guān)推薦

2021-01-21 16:03:15

Java文本編輯器編程語(yǔ)言

2020-09-18 06:00:51

開(kāi)源Markdown編輯器

2023-09-10 23:22:33

Zettlr筆記編輯器

2017-05-23 19:19:16

開(kāi)源Markdown編輯器

2021-10-27 14:55:57

Mark TextMarkdown編輯器

2016-08-02 10:35:40

LinuxMarkdown編輯器

2021-10-21 10:58:03

Markdown編輯器

2020-09-27 08:43:33

MuPythonturtle 模塊

2021-08-09 20:30:17

開(kāi)源框架頁(yè)面

2011-10-31 10:17:05

插件

2022-06-13 08:24:45

Typora編輯器

2022-01-10 18:16:24

編輯器Typora Markdown

2018-05-11 14:59:21

LinuxVim編輯器

2023-06-05 07:16:47

2009-02-26 08:54:50

FCKeditorHTML編輯器

2011-01-10 16:17:49

2022-03-03 20:57:53

代碼編輯器VS code

2021-11-24 09:12:11

Markdown編輯器Linux

2011-08-04 18:49:50

注冊(cè)表注冊(cè)表編輯器

2021-09-06 11:02:45

LinuxMarkdown編輯器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)