Python之tkinter文字區域Text使用及說明

文字區域Text 的基本概念

Entry控件主要是處理單行的文字,Text控件可以視為Entry的擴充,因為它可以處理多行的輸入,另外也可以在文字中嵌入圖像或是提供格式化功能,因此實際上我們將使Text當做簡單的文字處理軟件,甚至也可以當做網頁瀏覽器使用

它的構造方法如下:

Text(父對象, options, ...)

參數:

  • 第一個參數:父對象,表示這個文字區域將建立在哪一個窗口內
  • 第二個參數:options,參數如下
參數 含義
bg 或 background 背景色彩
bd 或 borderwidth 邊界寬度默認是2像素
cursor 當鼠標光標在文字區域上時光標形狀
exportselection 如果執行選擇操作時,所選擇的字符串會自動輸出至剪貼板,如果想要避免可以設置exportselection=0
fg 或 foreground 字形色彩
font 字形
height 高,單位是字符高,實際高度會是字符高度而定
highlightbackground 當文本框取得焦點時的背景顏色
highlightcolor 當文本框取得焦點時的顏色
highlightthickness 取得焦點時的厚度默認值是1
insertbackground 插入光標的顏色默認是黑色
insertborderwidth 圍繞插入遊標的3D厚度默認是0
padx Text 左/右框與文字最左/最右的間距
pady Text 上/下框與文字最上/最下的間距
relief 可由此控制文字外框默認是relief=SUNKEN
selectbackground 被選取字符串的背景色彩
selectborderwidth 選取字符串時邊界厚度默認值是1
selectforeground 被選取字符串的前景色彩
state 輸入狀態默認是NORMAL,表示可以輸入,DISABLED則表示無法編輯
tab 可設置按Tab鍵,如何定位插入點
width Text的寬,單位是字符寬
wrap 可控制某行文字太長時的處理,當某行文字太長時,可從字符做斷行默認是wrap=CHAR當wrap=WORD時,隻能從字做斷行
xscrollcommand 在X軸使用滾動條
yscrollcommand 在Y軸使用滾動條

文字區域Text 的基本應用

例子:

import tkinter
root = tkinter.Tk()
text = tkinter.Text(root, height=2, width=15)
text.pack()
root.mainloop()

運行結果:

若是輸入文字超過兩行將導致第一行數據被隱藏,若是輸入更多行將造成更多文字被隱藏,雖然可以用移動光標的方式重新看到第1行文字,但是對於不瞭解程序結構的人而言,還是比較容易誤會文字區域的內容,最後要註意的是放大窗口並不會放大文字區域

插入文字insert()

insert() 可以將字符串插入指定的索引位置,它的使用格式如下:

insert(index, string)

index若是END或者是INSERT,表示將字符串插入文件末端位置

例子:

import tkinter
root = tkinter.Tk()
text = tkinter.Text(root, height=2, width=15)
text.pack()
text.insert(tkinter.END, 'Python\n')
text.insert(tkinter.INSERT, 'Tkinter')
root.mainloop()

運行結果:

Text 加上滾動條 Scrollbar 設計

如果內容過多,我們可以加入滾動條的設計

例子:

import tkinter
root = tkinter.Tk()
text = tkinter.Text(root, height=4, width=30)
text.pack(side=tkinter.LEFT)
yscrollbar = tkinter.Scrollbar(root)
yscrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
# 滾動條與text聯動
yscrollbar.config(command=text.yview)
# text與滾動條聯動
text.config(yscrollcommand=yscrollbar.set)
str = """很多人都喜歡房子清掃過後煥然一新的感覺。同樣,理完發的感覺也十分美好,因為多餘的東西去除瞭。
兒童是快樂的,因為他沒有過多的心事,也沒有不必要的憂慮。而成人則不同,
我們的生命中有太多的積壓物和太多想像出來的復雜以及一些擴大瞭的悲痛。
而生命的難度也正在於此,你要不斷清掃和放棄一些東西,因為“生命裡填塞的東西愈少,
就愈能發揮潛能”。記得一部戲裡,一個人對主人公說:“走吧,不要回頭,做不好不要回來。
”他的意思是讓他離開這裡,是希望不要讓過去拖累他。
"""
text.insert(tkinter.END, str)
root.mainloop()

運行結果:

加上X軸滾動條

例子:

import tkinter
root = tkinter.Tk()
# wrap="none" 讓文字不自動換行
text = tkinter.Text(root, height=4, width=30, wrap="none")
# X軸滾動條
xscrollbar = tkinter.Scrollbar(root, orient=tkinter.HORIZONTAL)
xscrollbar.pack(side=tkinter.BOTTOM, fill=tkinter.X)
# Y軸滾動條
yscrollbar = tkinter.Scrollbar(root)
yscrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
# 因為Python是按順序解析的,所以如果這個放在前面的話,就優選放置text瞭
text.pack()
# Y軸滾動條與text聯動
yscrollbar.config(command=text.yview)
# Y軸text與滾動條聯動
text.config(yscrollcommand=yscrollbar.set)
# X軸滾動條與text聯動
xscrollbar.config(command=text.xview)
# X軸text與滾動條聯動
text.config(xscrollcommand=xscrollbar.set)
str = """很多人都喜歡房子清掃過後煥然一新的感覺。同樣,理完發的感覺也十分美好,因為多餘的東西去除瞭。
兒童是快樂的,因為他沒有過多的心事,也沒有不必要的憂慮。而成人則不同,
我們的生命中有太多的積壓物和太多想像出來的復雜以及一些擴大瞭的悲痛。
而生命的難度也正在於此,你要不斷清掃和放棄一些東西,因為“生命裡填塞的東西愈少,
就愈能發揮潛能”。記得一部戲裡,一個人對主人公說:“走吧,不要回頭,做不好不要回來。
”他的意思是讓他離開這裡,是希望不要讓過去拖累他。
"""
text.insert(tkinter.END, str)
root.mainloop()

運行結果:

現在即使放大text也不會有所變化,但是我們可以通過fillexpand來設置

例子:

text.pack(fill=tkinter.BOTH, expand=True)

運行結果:

字形

在tkinter.font模塊中有Font方法,可以由此方法設定Font的相關參數,例如,family、size、weight、slant、underline、overstrike

family

family 用於設置Text 文字區域的字形

例子:

import tkinter
from tkinter.font import Font
# 改變字體
def familyChange(event):
    f = Font(family=famliyVar.get())
    text.configure(font=f)
root = tkinter.Tk()
# 建立family下拉列表
famliyVar = tkinter.StringVar()
familyFamily = ('Arial', 'Times', 'Courier')
famliyVar.set(familyFamily[0])
optionMenu = tkinter.OptionMenu(root, famliyVar, *familyFamily, command=familyChange)
optionMenu.pack(pady=2)
# 建立text
text = tkinter.Text(root, height=4, width=30)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
root.mainloop()

運行結果:

下拉框的下拉外觀很醜,我們可以進行優化

import tkinter.ttk
optionMenu = tkinter.ttk.OptionMenu(root, famliyVar, *familyFamily, command=familyChange)

其他的都可以不需要改變

運行結果:

現在看上方的GIF圖,就會發現一個bug,筆者不清楚這是因為不兼容還是本身就是這樣的,但是可以進行修改

例子:

修復ttk.OptionMenu組件在選擇後第一個選項消失的問題

familyFamily = ('', 'Arial', 'Times', 'Courier')
famliyVar.set(familyFamily[1])

運行結果:

隻要把前面索引為0的選項為空字符串,就可以瞭,然後設置默認索引為1

weight

weight用於設置text文字區域的字是否是粗體

例子:

import tkinter
from tkinter.font import Font
# 改變字體
def familyChange(event):
    f = Font(family=famliyVar.get())
    text.configure(font=f)
# 改變粗細
def weightChange(event):
    f = Font(weight=weightVar.get())
    text.configure(font=f)
root = tkinter.Tk()
# 建立工具欄
toolbar = tkinter.Frame(root, relief=tkinter.RAISED, borderwidth=1)
toolbar.pack(side=tkinter.TOP, fill=tkinter.X, padx=2, pady=1)
# 建立family下拉列表
famliyVar = tkinter.StringVar()
familyFamily = ('Arial', 'Times', 'Courier')
famliyVar.set(familyFamily[0])
optionFont = tkinter.OptionMenu(toolbar, famliyVar, *familyFamily, command=familyChange)
optionFont.pack(side=tkinter.LEFT, pady=2)
# 建立weight下拉列表
weightVar = tkinter.StringVar()
weightFamily = ('normal', 'bold')
weightVar.set(weightFamily[0])
optionWeight = tkinter.OptionMenu(toolbar, weightVar, *weightFamily, command=weightChange)
optionWeight.pack(side=tkinter.LEFT, pady=2)
# 建立text
text = tkinter.Text(root, height=4, width=30)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
root.mainloop()

運行結果:

size

size用於設置Text文字區域的字號

例子:

import tkinter
from tkinter.font import Font
from tkinter import ttk
# 改變字體
def familyChange(event):
    f = Font(family=famliyVar.get())
    text.configure(font=f)
# 改變粗細
def weightChange(event):
    f = Font(weight=weightVar.get())
    text.configure(font=f)
# 改變大小
def sizeChange(event):
    f = Font(size=sizeVar.get())
    text.configure(font=f)
root = tkinter.Tk()
# 建立工具欄
toolbar = tkinter.Frame(root, relief=tkinter.RAISED, borderwidth=1)
toolbar.pack(side=tkinter.TOP, fill=tkinter.X, padx=2, pady=1)
# 建立family下拉列表
famliyVar = tkinter.StringVar()
familyFamily = ('', 'Arial', 'Times', 'Courier')
famliyVar.set(familyFamily[1])
optionFont = ttk.OptionMenu(toolbar, famliyVar, *familyFamily, command=familyChange)
optionFont.pack(side=tkinter.LEFT, pady=2)
# 建立weight下拉列表
weightVar = tkinter.StringVar()
weightFamily = ('', 'normal', 'bold')
weightVar.set(weightFamily[1])
optionWeight = ttk.OptionMenu(toolbar, weightVar, *weightFamily, command=weightChange)
optionWeight.pack(side=tkinter.LEFT, pady=2)
# 建立size組合框
sizeVar = tkinter.IntVar()
size = ttk.Combobox(toolbar, textvariable=sizeVar)
sizeFamily = [x for x in range(8, 30)]
size['value'] = sizeFamily
size.current(4)
size.bind('<<ComboboxSelected>>', sizeChange)
size.pack(side=tkinter.LEFT, pady=2)
# 建立text
text = tkinter.Text(root, height=4, width=30)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
root.mainloop()

運行結果:

選取文字

Text對象的get()方法可以取得目前所選的文字,在使用Text文字區域時,如果有選取文字操作發生時,Text的對象會將所選文字的起始索引放在SEL_FIRST,結束索引放在SEL_LAST,將SEL_FIRSTSEL_LAST當做get方法的參數,就可以獲得目前所選的文字瞭

例子:

import tkinter
def show():
    try:
        textInfo = text.get(tkinter.SEL_FIRST, tkinter.SEL_LAST)
        print(textInfo)
    except tkinter.TclError:
        print('沒有選取文字')
root = tkinter.Tk()
# 建立Button
button = tkinter.Button(root, text="Print", command=show)
button.pack(pady=3)
# 建立text
text = tkinter.Text(root, height=4, width=30)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'Text對象的get()方法可以取得目前所選的文字')
root.mainloop()

運行結果:

認識Text 的索引

Text對象的索引並不是單一數字,而是一個字符串,索引的目的是讓Text控件處理更進一步的文件操作,下列是常見的索引形式

  • line/column('line.column'):計數方式line是從1開始,column從0開始計數,中間用句點分割
  • INSERT:目前插入點的位置
  • CURRENT:光標目前位置相對於字符的位置
  • END:緩沖區最後一個字符後的位置

表達式Expression:索引使用表達式

  • +count chars:count 是數字,例如,"+2c" 索引往後移動兩個字符
  • -count chars:count 是數字,例如,"-2c" 索引往前移動兩個字符

例子:

try:
    textInfo = text.get(tkinter.SEL_FIRST, tkinter.SEL_LAST)
    print(textInfo)
    print('start:' + text.index(tkinter.SEL_FIRST))
    print('end:' + text.index(tkinter.SEL_LAST))
except tkinter.TclError:
    print('沒有選取文字')

運行結果:

例子:

列出INSERT、CURRENT、END的位置

import tkinter
def show():
    print('INSERT  :', text.index(tkinter.INSERT))
    print('CURRENT :', text.index(tkinter.CURRENT))
    print('END     :', text.index(tkinter.END))
root = tkinter.Tk()
# 建立Button
button = tkinter.Button(root, text="Print", command=show)
button.pack(pady=3)
# 建立text
text = tkinter.Text(root, height=4, width=30)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'Text對象的get()方法\n可以取得目前所選的文字')
root.mainloop()

運行結果:

由於鼠標光標一直在Print按鈕上,所以列出的CURRENT是在1.0索引位置,其實如果我們在文件位置單擊時,CURRENT的索引位置會變動,此時INSERT的索引位置會隨著CURRENT更改

例子:

在指定索引位置插入文字

import tkinter
root = tkinter.Tk()
# 建立text
text = tkinter.Text(root, height=4, width=30)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'Text對象的get()方法\n')
text.insert(1.2, '可以取得目前所選的文字')
root.mainloop()

運行結果:

建立書簽 Marks

在編輯文件時,可以在文件特殊位置建立書簽(Marks),方便查閱,書簽是無法顯示的,但會在編輯系統內被記錄,如果書簽內容被刪除,則此書簽也將自動被刪除,其實在tkinter內默認有兩個書簽,INSERT和CURRENT

書簽的相關方法

  • index(mark):傳回指定書簽的line和column
  • mark_names():傳回這個Text對象所有的書簽
  • mark_set(mark, index):在指定的index位置設置書簽
  • mark_unset:取消指定書簽設置

例子:

import tkinter
root = tkinter.Tk()
# 建立text
text = tkinter.Text(root)
# 插入內容
for i in range(1, 10):
    text.insert(tkinter.END, str(i) + ' I Like Python and Tkinter\n')
# 設置書簽
text.mark_set('markOne', 3.0)
text.mark_set('markTwo', 5.0)
print(text.get('markOne', 'markTwo'))
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
root.mainloop()

運行結果:

3 I Like Python and Tkinter
4 I Like Python and Tkinter

建立標簽

標簽(Tags)是指一個區域文字,然後我們可以為這個區域取一個名字,這個名字稱為標簽,可以使用此標簽名字代表這個區域名字。

有瞭標簽後,我們可以針對此標簽做進一步的工作,例如,將字形、色彩等的應用在此標簽上。

下列是常見的標簽方法

  • tag_add(tagname, startindex[, endindex] ···):將startindex和endindex間的文字命名為tagname標簽
  • tag_conig(tagname, options, ···):可以為標簽執行特定的編輯,或動作綁定
  • tag_delete(tagname):刪除此標簽,同時移除此標簽特殊的編輯或綁定
  • tag_remove(tagname[, startindex[, endindex]] ···):刪除標簽,但是不移除此標簽特殊的編輯或綁定

tag_conig的參數:

參數 含義
background 背景顏色
borderwidth 文字外圍厚度默認是0
font 字形
foreground 前景顏色
justify 對齊方式默認是LEFT,也可以是RIGHT或CENTER
oversticky 如果是True,加上刪除線
underline 如果是True,加上下劃線
wrap 當使用wrap模式時,可以使用NONE、CHAR或WORD

例子:

import tkinter
root = tkinter.Tk()
# 建立text
text = tkinter.Text(root)
# 插入內容
for i in range(1, 10):
    text.insert(tkinter.END, str(i) + ' I Like Python and Tkinter\n')
# 設置書簽
text.mark_set('markOne', 3.0)
text.mark_set('markTwo', 5.0)
# 設置標簽
# 在區間markOne 與 markTwo之間設置標簽tag1
text.tag_add('tag1', 'markOne', 'markTwo')
# 為標簽添加屬性
text.tag_config('tag1', foreground='blue', background='lightyellow')
text.pack(fill=tkinter.BOTH, expand=True)
root.mainloop()

運行結果:

除瞭可以使用tag_add()自行定義標簽外,系統還有一個內建標簽SEL,代表所選取的區間

例子:

選取文字時,可以依所選的文字大小顯示所選文字

import tkinter
from tkinter.font import Font
from tkinter.ttk import *
def sizeSelected(event):
    # 把當前Combobox的值,傳遞給Font
    f = Font(size=sizeVar.get())
    # 添加標簽,SEL是選取的區間,然後選取的區間的font就是Combobox的值
    text.tag_config(tkinter.SEL, font=f)
root = tkinter.Tk()
root.geometry('200x150')
# 建立工具欄
toolbar = tkinter.Frame(root, relief=tkinter.RAISED, borderwidth=1)
# 放在頂端,填充X軸
toolbar.pack(side=tkinter.TOP, fill=tkinter.X, padx=2, pady=1)
# 在工具欄上創建字體選擇combobox組合框
sizeVar = tkinter.IntVar()
size = Combobox(toolbar, textvariable=sizeVar)
# 列表推導式,選取Combobox的value范圍
sizeFamily = [x for x in range(8, 30)]
size['value'] = sizeFamily
# 設置默認選項,索引為4
size.current(4)
# 綁定Combobox事件,
size.bind('<<ComboboxSelected>>', sizeSelected)
size.pack()
# 建立text
text = tkinter.Text(root)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'I Like Event!')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
# 設置焦點
text.focus_set()
root.mainloop()

運行結果:

我們也可以在insert()方法的第三個參數增加標簽tag

例子:

import tkinter
root = tkinter.Tk()
root.geometry('200x150')
# 建立text
text = tkinter.Text(root)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'I Like Event!\n', 'a')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
# 設置焦點
text.focus_set()
# 將Tag a設為居中,藍色,含有下劃線
text.tag_config('a', foreground='blue', justify=tkinter.CENTER, underline=True)
root.mainloop()

運行結果:

Cut/Copy/Paste 功能

編輯文件時剪貼/復制/粘貼(Cut/Copy/Paste)是很常見的功能,這些功能其實已經被內建在tkinter中,但是為瞭學習,我們還是得掌握基本的方法

刪除插入點字符

delete(INSERT)                  # 刪除插入點字符

刪除所選的文本塊,可以使用兩個參數:起始索引與結束索引

delete(SEL_FIRST, SEL_LAST)     # 刪除所選文本塊
delete(startindex, endindex)    # 刪除指定區間文本塊

刪除整份文件

delete(1.0, END)

例子:

import tkinter
def show(event):
    popupment.post(event.x_root, event.y_root)
# 剪貼
def cutJob():
    # 調用下面的copyJoy方法
    copyJob()
    # 刪除所選取的文字
    text.delete(tkinter.SEL_FIRST, tkinter.SEL_LAST)
# 復制
def copyJob():
    try:
        # 清除剪貼板
        text.clipboard_clear()
        # 復制選取內容
        copyText = text.get(tkinter.SEL_FIRST, tkinter.SEL_LAST)
        # 寫入剪貼板
        text.clipboard_append(copyText)
    except tkinter.TclError:
        print('沒有選取')
# 粘貼
def pasteJob():
    try:
        # 讀取剪貼板內容
        copyText = text.selection_get(selection='CLIPBOARD')
        # 插入內容
        text.insert(tkinter.INSERT, copyText)
    except tkinter.TclError:
        print('剪貼板沒有內容')
root = tkinter.Tk()
root.geometry('200x150')
# 名字可以隨便取,tearoff是取消分割線,分割線很醜
popupment = tkinter.Menu(root, tearoff=False)
# 在彈出菜單內建立三個命令列表
popupment.add_command(label='Cut', command=cutJob)
popupment.add_command(label='Copy', command=copyJob)
popupment.add_command(label='Paste', command=pasteJob)
# 單擊鼠標右鍵綁定顯示彈出菜單
root.bind('<3>', show)
# 建立text
text = tkinter.Text(root)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

使用內建的虛擬方法重新設計復制粘貼剪貼

# 剪貼
def cutJob():
    text.event_generate('<<Cut>>')
# 復制
def copyJob():
    text.event_generate('<<Copy>>')
# 粘貼
def pasteJob():
    text.event_generate('<<Paste>>')

隻需要小改一下即可,就是辣麼簡單,但是簡單歸簡單,還是得掌握基本的方法與思路

撤銷與恢復

Text控件有一個簡單撤銷(undo)和恢復(redo)的機制, 這個機制可以應用於文字刪除(delete)和文字插入(insert)。

Text控件默認環境下沒有開啟這個機制的,如果要使用此功能,可以在Text()方法內增加undo=True參數

例子:

import tkinter
def show(event):
    popupment.post(event.x_root, event.y_root)
# 剪貼
def cutJob():
    text.event_generate('<<Cut>>')
# 復制
def copyJob():
    text.event_generate('<<Copy>>')
# 粘貼
def pasteJob():
    text.event_generate('<<Paste>>')
# 撤銷
def undoJob():
    try:
        text.edit_undo()
    except tkinter.TclError:
        print('先前沒有動作')
# 恢復
def redoJob():
    try:
        text.edit_redo()
    except tkinter.TclError:
        print('先前沒有動作')
root = tkinter.Tk()
root.geometry('200x150')
# 名字可以隨便取,tearoff是取消分割線,分割線很醜
popupment = tkinter.Menu(root, tearoff=False)
# 在彈出菜單內建立三個命令列表
popupment.add_command(label='Cut', command=cutJob)
popupment.add_command(label='Copy', command=copyJob)
popupment.add_command(label='Paste', command=pasteJob)
# 單擊鼠標右鍵綁定顯示彈出菜單
root.bind('<3>', show)
# 建立工具欄
toolbar = tkinter.Frame(root, relief=tkinter.RAISED, borderwidth=1)
toolbar.pack(side=tkinter.TOP, fill=tkinter.X, padx=2, pady=1)
# 在工具欄上建立undo與redo按鈕
undoButton = tkinter.Button(toolbar, text='Undo', command=undoJob)
undoButton.pack(side=tkinter.LEFT, padx=2, pady=1)
redoButton = tkinter.Button(toolbar, text='Redo', command=redoJob)
redoButton.pack(side=tkinter.LEFT, padx=2, pady=1)
# 建立text, undo一定要開
text = tkinter.Text(root, undo=True)
text.pack(fill=tkinter.BOTH, expand=True, padx=3, pady=2)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

有點類似上一步和復原

第63行的undo=True一定要開,增加瞭這個參數後,程序的第26行就可以用text對象調用edit_undo()方法,這個方法會自動執行Undo動作。程序的34行就可以用text對象調用edit_redo()方法,這個方法會自動執行Redo動作

查找文字

在Text控件內可以使用search()方法茶軸指定的字符串,這個方法會傳回找到的第一個指定字符串的索引。假設Text控件的對象是text,語法如下:

pos = text.search(key, startindex, endindex)
  • pos:傳回所找到的字符串的索引位置,如果查找sibai失敗則傳回空字符串
  • key:所查找的字符串
  • startindex:查找起始位置
  • endindex:查找結束位置,如果查找到文檔最後可以使用END

例子:

import tkinter
def search():
    # 刪除標簽但不刪除標簽定義
    text.tag_remove('found', '1.0', tkinter.END)
    # 設置起始值為1.0,也就是第一排第0個字符
    start = 1.0
    # 獲取輸入框的值
    key = entry.get()
    # 沒有輸入時
    if len(key.strip()) == 0:
        # 就當什麼都沒有發生
        return -1
    # 死循環,因為我們查找的可能不止一個值,可能文本框中有多個
    while True:
        # 執行查找,key是我們需要查詢的,start是起始值,END是從頭查到尾
        pos = text.search(key, start, tkinter.END)
        # 查不到就結束,break是退出死循環
        if pos == '':
            break
        # 進行到這一步說明查到瞭數據
        # 添加標簽名,pos是查詢到的索引位置,後面這個我下面詳講
        text.tag_add('found', pos, '%s+%dc' % (pos, len(key)))
        # 這裡是更新查找起始位置
        start = '%s+%dc' % (pos, len(key))
root = tkinter.Tk()
root.geometry('200x150')
root.rowconfigure(1, weight=1)
root.columnconfigure(0, weight=1)
# 輸入的文本框
entry = tkinter.Entry()
entry.grid(row=0, column=0, padx=5, pady=5, sticky=tkinter.W + tkinter.E)
# 查找按鈕
btu = tkinter.Button(root, text='find', command=search)
btu.grid(row=0, column=1, padx=5, pady=5)
# 建立text
text = tkinter.Text(root, undo=True)
text.grid(row=1, column=0, columnspan=2, padx=3, pady=5, sticky=tkinter.W + tkinter.E + tkinter.N + tkinter.S)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
# 定義找到的標簽
text.tag_configure('found', background='yellow')
root.mainloop()

運行結果:

第19行:

  • pos = text.search(key, start, tkinter.END)
  • key:查找關鍵字
  • start:查找起始值
  • END:查找終止值

第25行:

  • text.tag_add('found', pos, '%s+%dc' % (pos, len(key)))
  • 我們之前刪除瞭標簽但沒有刪除屬性,也就是背景顏色,這裡重新添加一下found標簽,可以自動得到它的屬性,然後後面的pos是我們查找到的字符串的起始值
  • %s+%dc’ % (pos, len(key))):索引使用表達式,假設pos是1.2,key是like,len(key)就是4,然後這個就是1.2+4c,+4c就是索引往後移動兩個字符,這裡要註意%dc是分開的,表達式值就是1.6瞭,也就是查找字符的終止值,不要想復雜瞭

第27行:

  • 更新查找起始位置,將光標定位在已查找字符的終止值,讓它繼續往後查找~~

存儲Text 控件內容

當使用編輯程序完成文件的編排後,下一步就是將所編排的文件存儲

例子

import tkinter
def save():
    # 獲取全部內容
    textContext = text.get('1.0', tkinter.END)
    filename = 'new name.txt'
    with open(filename, 'w') as output:
        output.write(textContext)
        root.title(filename)
root = tkinter.Tk()
root.title('Untitled')
root.geometry('200x150')
# 建立菜單欄
menubar = tkinter.Menu(root)
# 建立菜單類別對象,命名為file
filemenu = tkinter.Menu(menubar, tearoff=False)
menubar.add_cascade(label='File', menu=filemenu)
# 在file裡面建立子菜單列表
filemenu.add_command(label='Save', command=save)
filemenu.add_command(label='Exit', command=root.destroy)
# 顯示菜單對象
root.config(menu=menubar)
# 建立text
text = tkinter.Text(root, undo=True)
text.pack(fill=tkinter.BOTH, expand=True)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

他會直接存在當前文件位置

但是這樣不太美觀,不是GUI設計方式,在GUI的設計中應該是啟動’另存為’,然後可以選擇將文檔存儲的文檔夾再輸入文件名。

tkinter.filedialog模式中有asksaveasfilename()方法,我們可以使用此方法,讓窗口出現對話框,再執行存儲工作

例子

import tkinter
from tkinter.filedialog import asksaveasfilename
def saveAs():
    # 獲取全部內容
    global filename
    textContext = text.get('1.0', tkinter.END)
    filename = asksaveasfilename()
    if filename == '':
        return
    with open(filename, 'w') as output:
        output.write(textContext)
        root.title(filename)
filename = 'Untitled'
root = tkinter.Tk()
root.title(filename)
root.geometry('200x150')
# 建立菜單欄
menubar = tkinter.Menu(root)
# 建立菜單類別對象,命名為file
filemenu = tkinter.Menu(menubar, tearoff=False)
menubar.add_cascade(label='File', menu=filemenu)
# 在file裡面建立子菜單列表
filemenu.add_command(label='Save As', command=saveAs)
filemenu.add_command(label='Exit', command=root.destroy)
# 顯示菜單對象
root.config(menu=menubar)
# 建立text
text = tkinter.Text(root, undo=True)
text.pack(fill=tkinter.BOTH, expand=True)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

運行結果:正規的文字編輯程序中,需要考慮的事項太多瞭,有Save命令,可以直接使用目前文件名存儲文件,如果尚未存盤才出現另存為對話框,還有可以使用快捷鍵方式快捷保存

上述的方式,如果我們在輸入文件名的時候沒有加後綴.txt的話,會直接幫我們保存一個無格式的文件,所以一定要加後綴,下面的一種方式可以幫我們默認加後綴

例子:

filename = asksaveasfilename(defaultextension='.txt')

這樣我們就不要刻意去輸入後綴,前提是文件就應該是txt文件格式~

新建文檔

在設計編輯程序時,有時候想要新建文檔,這時編輯程序會將編輯去清空,以供編輯新的文檔,設計方式如下:

  • 刪除Text控件內容,參考第5行
  • 將窗口標題改為'Untitled',參考第6行

例子:

import tkinter
from tkinter.filedialog import asksaveasfilename
def newFile():
    text.delete('1.0', tkinter.END)
    root.title('Untitled')
def saveAs():
    # 獲取全部內容
    global filename
    textContext = text.get('1.0', tkinter.END)
    # 開啟另存為對話框,默認所存的文件格式是txt
    filename = asksaveasfilename(defaultextension='.txt')
    if filename == '':
        return
    with open(filename, 'w') as output:
        output.write(textContext)
        root.title(filename)
filename = 'Untitled'
root = tkinter.Tk()
root.title(filename)
root.geometry('200x150')
# 建立菜單欄
menubar = tkinter.Menu(root)
# 建立菜單類別對象,命名為file
filemenu = tkinter.Menu(menubar, tearoff=False)
menubar.add_cascade(label='File', menu=filemenu)
# 在file裡面建立子菜單列表
filemenu.add_command(label='New File', command=newFile)
filemenu.add_command(label='Save As', command=saveAs)
filemenu.add_separator()
filemenu.add_command(label='Exit', command=root.destroy)
# 顯示菜單對象
root.config(menu=menubar)
# 建立text
text = tkinter.Text(root, undo=True)
text.pack(fill=tkinter.BOTH, expand=True)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

打開文檔

在tkinter.filedialog模塊中有askopenfilename()方法,可以使用此方法,讓窗口出現對話框,再執行選擇所要打開的文檔

filename = askopenfilename()

上述程序可以傳回所存盤文檔的路徑(含文件夾),然後可以使用open方法打開文檔,最後將所打開的文檔插入Text控件。步驟如下

  • 在打開對話框中選擇欲打開的文檔,參考第13行
  • 使用open File()方法打開文檔,參考第21行
  • 使用read()方法讀取文檔內容,參考第23行
  • 刪除Text控件內容,參考第25行
  • 將所讀取的文檔內容插入Text控件,參考第27行
  • 更改窗口標題名稱,參考第29行

例子:

import tkinter
from tkinter.filedialog import asksaveasfilename
from tkinter.filedialog import askopenfilename
def newFile():
    text.delete('1.0', tkinter.END)
    root.title('Untitled')
def openFile():
    # 改變變量屬性
    global filename
    # 讀取打開的文檔
    filename = askopenfilename()
    # 如果沒有選擇文檔
    if filename == '':
        # 就當什麼都沒有發生
        return
    # 打開文檔
    with open(filename, 'r') as file:
        # 讀取文檔的內容
        context = file.read()
    # 刪除text控件的內容
    text.delete('1.0', tkinter.END)
    # 插入所讀取的內容
    text.insert(tkinter.END, context)
    # 改標題
    root.title(filename)
def saveAs():
    # 獲取全部內容
    global filename
    textContext = text.get('1.0', tkinter.END)
    # 開啟另存為對話框,默認所存的文件格式是txt
    filename = asksaveasfilename(defaultextension='.txt')
    if filename == '':
        return
    with open(filename, 'w') as output:
        output.write(textContext)
        root.title(filename)
filename = 'Untitled'
root = tkinter.Tk()
root.title(filename)
root.geometry('200x150')
# 建立菜單欄
menubar = tkinter.Menu(root)
# 建立菜單類別對象,命名為file
filemenu = tkinter.Menu(menubar, tearoff=False)
menubar.add_cascade(label='File', menu=filemenu)
# 在file裡面建立子菜單列表
filemenu.add_command(label='New File', command=newFile)
filemenu.add_command(label='Open File', command=openFile)
filemenu.add_command(label='Save As', command=saveAs)
filemenu.add_separator()
filemenu.add_command(label='Exit', command=root.destroy)
# 顯示菜單對象
root.config(menu=menubar)
# 建立text
text = tkinter.Text(root, undo=True)
text.pack(fill=tkinter.BOTH, expand=True)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

默認含滾動條的ScrolledText 控件

正式的文本編輯程序應該要設計滾動條,我們可以采用之前的設計方式來設計滾動條。在tkinter.scrolledtext模塊內有ScrolledText控件,這是一個默認含有滾動條的Text控件,使用時可以先導入此模塊,執行時就可以看到滾動條

例子:

import tkinter
from tkinter.filedialog import asksaveasfilename
from tkinter.filedialog import askopenfilename
def newFile():
    text.delete('1.0', tkinter.END)
    root.title('Untitled')
def openFile():
    # 改變變量屬性
    global filename
    # 讀取打開的文檔
    filename = askopenfilename()
    # 如果沒有選擇文檔
    if filename == '':
        # 就當什麼都沒有發生
        return
    # 打開文檔
    with open(filename, 'r') as file:
        # 讀取文檔的內容
        context = file.read()
    # 刪除text控件的內容
    text.delete('1.0', tkinter.END)
    # 插入所讀取的內容
    text.insert(tkinter.END, context)
    # 改標題
    root.title(filename)
def saveAs():
    # 獲取全部內容
    global filename
    textContext = text.get('1.0', tkinter.END)
    # 開啟另存為對話框,默認所存的文件格式是txt
    filename = asksaveasfilename(defaultextension='.txt')
    if filename == '':
        return
    with open(filename, 'w') as output:
        output.write(textContext)
        root.title(filename)
filename = 'Untitled'
root = tkinter.Tk()
root.title(filename)
root.geometry('200x150')
# 建立菜單欄
menubar = tkinter.Menu(root)
# 建立菜單類別對象,命名為file
filemenu = tkinter.Menu(menubar, tearoff=False)
menubar.add_cascade(label='File', menu=filemenu)
# 在file裡面建立子菜單列表
filemenu.add_command(label='New File', command=newFile)
filemenu.add_command(label='Open File', command=openFile)
filemenu.add_command(label='Save As', command=saveAs)
filemenu.add_separator()
filemenu.add_command(label='Exit', command=root.destroy)
# 顯示菜單對象
root.config(menu=menubar)
# 建立text
text = tkinter.Text(root, undo=True)
text.pack(fill=tkinter.BOTH, expand=True)
text.insert(tkinter.END, 'I Like Event!\n')
text.insert(tkinter.END, 'I Like Python!\n')
text.insert(tkinter.END, 'I Like Command!\n')
text.insert(tkinter.END, 'I Like Combobox!\n')
text.insert(tkinter.END, 'I Like Text!\n')
text.insert(tkinter.END, 'I Like Font!\n')
root.mainloop()

運行結果:

插入圖像

Text控件時允許插入圖像文件的,所插入的圖像文件會被視為一個字符方式進行處理,所程璇的大小是實際圖像的大小

例子:

import tkinter
from PIL import Image, ImageTk
root = tkinter.Tk()
img = Image.open('coat.png')
myPng = ImageTk.PhotoImage(img)
text = tkinter.Text(root)
text.image_create(tkinter.END, image=myPng)
text.insert(tkinter.END, '\n')
text.insert(tkinter.END, '小小嬰兒上衣~')
text.pack(fill=tkinter.BOTH, expand=True)
root.mainloop()

運行結果:

總結

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: