GUI的最終選擇 Tkinter(五):Text用法


Text組件

繪制單行文本使用Label組件,多行選使用Listbox,輸入框使用Entry,按鈕使用Button組件,還有Radiobutton和Checkbutton組件用於提供單選或多選的情況,多個組件可以使用Frame組件先搭建一個框架,這樣組合起來顯示好看點,最后還學習了Scrollbar和Scale,Scrollbar組件用於實現滾動條,而Scale則是讓用戶在一個范圍內選擇一個確定的值。

Text(文本)組件用於顯示和處理多行文本。在Tkinter的所有組件中,Text組件顯得異常強大和靈活,它適用於處理多種任務,雖然該組件的蛀牙牡蠣是顯示多行文本,但它長城被用於作為簡單的文本編輯器和網頁瀏覽器使用。

當創建一個Text組件的時候,它里面是沒有內容的,為了給其插入內容,可以利用insert()方法以及INSERT或END索引號:

1 from tkinter import *
2 
3 root = Tk()
4 text = Text(root,width=20,height=15)
5 text.pack()
6 text.insert(INSERT,"Python3 \n") #INSERT索引表示插入光標當前的位置
7 text.insert(END,"python算法")
8 mainloop()

執行結果:

Text組件不僅支持插入和編輯文本,它還支持插入image對象和windows組件。

 1 from tkinter import *
 2 
 3 root = Tk()
 4 text = Text(root,width=20,height=15)
 5 text.pack()
 6 text.insert(INSERT,"I love Python3") #INSERT索引表示插入光標當前的位置
 7 def show():
 8     print("被點了一下。。。")
 9 b1 = Button(text,text="點我",command=show)
10 text.window_create(INSERT,window=b1)
11 mainloop()

 執行結果:

下面代碼將實現單擊顯示一張圖片

 1 from tkinter import *
 2 
 3 root = Tk()
 4 text = Text(root,width=20,height=15)
 5 text.pack()
 6 photo = PhotoImage(file='bg.gif')
 7 def show():
 8     text.image_create(END,image=photo)
 9 b1 = Button(text,text="點我",command=show)
10 text.window_create(INSERT,window=b1)
11 mainloop()

執行結果:

 

Indexes用法

Indexes(索引)是用來指向Text組件中文本的位置,跟Python的序列索引一樣,Text組件索引也是對應實際字符之間的位置。

Tkinter提供一系列不同的索引類型:

  • “line.column”(行/列)
  • “line.end”(某一行的末尾)
  • INSERT
  • CURRENT
  • END
  • user-defined marks
  • user-defined tags("tag.first","tag.last")
  • selection(SELFIRST.SELLAST)
  • window coordinate("@x,y")
  • embedded object name(window,images)
  • expressions

1. "line.column‘’

用行號和列號組成的字符串是常用的索引方法,它們將索引位置的行號和列號以字符串的形式表示出來(中間以“.”分隔,例如“1.0”)。需要注意的是:行號以1開始,列號則以0開始,還可以使用一下語法建索引:

“%d.%d”%(line,column)

指定超出現有文本的最后一行的行號,或超出一行中列數的列號都不會引發錯誤。對於這樣的指定,Tkinter解釋為已有內容的末尾的下一個位置。

需要注意的是,使用“行/列”的索引方式看起來像是浮點值,其實在需要指定索引的時候使用浮點值代替也是可以的:

 1 from tkinter import *
 2 
 3 root = Tk()
 4 text = Text(root,width=20,height=15)
 5 text.pack()
 6 def show():
 7     text.insert(INSERT, "i love python")
 8     print(text.get("1.2", 1.6))
 9 b1 = Button(text,text="點我",command=show)
10 text.window_create(INSERT,window=b1)

執行結果:

2. “line.end”

行號加上字符串“.end”的格式表示該行最后一個字符串的位置:

from tkinter import *

root = Tk()
text = Text(root,width=20,height=15)
text.pack()
def show():
    text.insert(INSERT, "i love python")
    print(text.get("1.2", "1.end"))
b1 = Button(text,text="點我",command=show)
text.window_create(INSERT,window=b1)

mainloop()

執行結果:

3. INSERT(或“insert”)

對應插入光標的位置

4. CURRENT(或“current”)

對應與鼠標坐標最接近的位置。不過,如果你緊按鼠標任何一個按鈕,會直接到你松開才相應。

5. END(或“end”)

對應Text組件的文本緩沖區最后一個字符的下一個位置。

6. user-defined marks

user-defined marks是對Text組件中位置的命名。INSERT和CURRENT是兩個預先命名好的marks,除此之外可以自定義marks。

7. User-defined tags

User-defined tags代表可以分配給Text組件的特殊事件綁定和風格。、

可以使用“tag.first”(使用tag的未必能是第一個字符之間)和“tag.last”(使用tag的文本的最后一個字符之后)語法表示標簽的范圍:

“%s.first”%tagname 

“%s.last”%tagnam 

8. selection(SELFIRST,SELLAST)

selection是一個名為SEL(或“sel”)的特殊tag,表示當前被選中的范圍,可以使用SELFIRST和SELLAST來表示這個范圍如果沒有選中的內容,那么Tkinter會拋出一個TclError異常。

9. windows coordinate("@x.y")

可以使用串口坐標作為索引。例如在一個時間綁定中,你可以使用以下代碼找到最接近的鼠標字符:

“@%d,%d”%(event.x,event.y)

 

10. embedded object name(window,images)

embedden object name 用於指向在Text組件中嵌入的window和image對象。要引用一個window,只要簡單地講一個Tkinter組件實例作為索引即可。引用一個嵌入的image,只需要使用相應的PhotoImage和BitmapImage對象。

11. expressions

expressions用於修改任何格式的索引,用字符串的形式實現修改索引的表達式,具體表達式實現如表:

表達式 含義
"+count chars" 將索引向前(->)移動count個字符。可以越過換行符,但不能超過END的位置
"-count chars" 將索引向后(<-)移動count個字符。可以越過換行符,但不能超過"1.0"的位置
"+count lines" 將索引向前(->)移動count行,索引會盡量保持與移動前在同一列上,但如果移動后的那一行字符太少,將移動到該行的末尾。
"-count lines" 將索引向后(,-)移動count行,索引會盡量保持與移動前在同一列上,但如果移動后的那一行字符太少,將移動到該行的末尾。
"linestart" 將索引移動到當前索引所在行的起始位置。注意:使用的該表達式前面必須用一個空格隔開
"lineend" 將索引移動到當前索引所在行的末尾位置。注意:使用的該表達式前面必須用一個空格隔開
"wordstart" 將索引移動到當前索引指向的單詞的開頭。單詞的定義是一系列字母、數字、下划線或任何為空白字符的組合。注意:使用該表達式前面必須用一個空格隔開
"wordend" 將索引移動到當前索引指向的單詞的末尾。單詞的定義是一系列字母、數字、下划線或任何為空白字符的組合。注意:使用該表達式前面必須用一個空格隔開

提示:只要結果不產生歧義,關鍵字可以被縮寫,空格可以是省略的,例如:“+ 5chars”可以縮寫為“+5c”

在實現中,為了確保表達式為普通字符串,你可以使用str或格式化操作來創建一個表達式字符串。來看下面列子,刪除插入光標前面的一個字符。

def backspace(event):
    event.widgt.delete("%s-1c"%INSERT,INSERT)

Marks用法

Marks通常是指嵌入到Text組件文本中的不可見對象,簡單的說就是指定字符串間的位置,它會跟着相應的字符一起移動。Marks有INSERT,CURRENT和user-defined marks(用戶自定義的Marks)。其中,INSERT和CURRENT是Tkinter預定義的特殊Marks,它不能夠被刪除。

INSERT(或insert)用於指定當前插入的光標的而為之,Tkinter會在該位置繪制一個閃爍的光標(因此並不是所有的Marks都不可見)。

CURRENT(或current)用於指定與與鼠標坐標最接近的位置。不過,如果你緊按鼠標任何一個按鈕,它會知道你松開才響應。

還可以自定義任意數量的Marks,Marks的名字是由普通字符串組成,可以是除了空白字符的任何字符(為了避免歧義,你應該起一個有意義的名字),使用mark_ser()方法創建和移動Marks.

如果在一個Marks標記的位置之前插入或刪除文本,那么Marks跟着一並移動,刪除Marks需要使用mark_unset()方法,刪除Marks周圍的文本並並不會刪除Marks本身。

其實Marks事實上就是索引,用於表示位置:

1 from tkinter import *
2 root = Tk()
3 text = Text(root,width=30,height=10)
4 text.pack()
5 text.insert(INSERT,'I love python')
6 text.mark_set("here","1.2")
7 text.insert('here',"")
8 mainloop()

執行結果:

再如,如果Marks前邊的內容發生改變,那么Marks的位置也會跟着移動(實際上,就是Mark會記住它后面的內容)

1 from tkinter import *
2 root = Tk()
3 text = Text(root,width=30,height=10)
4 text.pack()
5 text.insert(INSERT,'I love python')
6 text.mark_set("here","1.2")
7 text.insert('here',"")
8 text.insert('here',"")
9 mainloop()

執行結果:

再如,如果Marks周圍的文本被刪了,Mark仍然在:

 1 from tkinter import *
 2 root = Tk()
 3 text = Text(root,width=30,height=10)
 4 text.pack()
 5 text.insert(INSERT,'I love python')
 6 text.mark_set("here","1.2")
 7 text.insert('here',"")
 8 text.delete('1.0',END)
 9 text.insert('here',"")
10 mainloop()

執行結果:

再如,只有mark_unset()方法可以解除Mark的封印;

 1 from tkinter import *
 2 root = Tk()
 3 text = Text(root,width=30,height=10)
 4 text.pack()
 5 text.insert(INSERT,'I love python')
 6 text.mark_set("here","1.2")
 7 text.insert('here',"")
 8 text.mark_unset("here")
 9 text.delete('1.0',END)
10 text.insert('here',"")
11 mainloop()

錯誤信息:

---------------------------------------------------------------------------
TclError                                  Traceback (most recent call last)
<ipython-input-7-2c32c5656dea> in <module>()
      8 text.mark_unset("here")
      9 text.delete('1.0',END)
---> 10 text.insert('here',"")
     11 mainloop()

c:\python36\lib\tkinter\__init__.py in insert(self, index, chars, *args)
   3264         """Insert CHARS before the characters at INDEX. An additional
   3265         tag can be given in ARGS. Additional CHARS and tags can follow in ARGS."""
-> 3266         self.tk.call((self._w, 'insert', index, chars) + args)
   3267     def mark_gravity(self, markName, direction=None):
   3268         """Change the gravity of a mark MARKNAME to DIRECTION (LEFT or RIGHT).

TclError: bad text index "here"

 

默認插入內容到Mark,是插入到他的左側(就是說插入一個字符的話,Mark向后移動了一個字符的位置)。那么能不能插入到Mark的右側了?答案是可以的,通過mark_gravity()方法就可以實現。 

Tags用法

 Tags(標簽)通常用於改變Text組件中內容的樣式和功能。可以用來修改文本的字體,尺寸和顏色。另外,Tags還允許將文本,嵌入的組件和圖片與鍵盤鼠標等事件相關聯。除了user-defined tags(用戶自定義的Tags),還有一個預定義的特殊Tags:SEL.

SEL(或sel)用於表示對象的選中內容(如果有的話)

可以自定義任意數量的Tags,Tags的名字是有普通字符串組成,可以是除了空白字符以外的額任意字符。另外,任何文本內容都支持多個Tags描述,任何Tags也可以用於描述多個不同的文本內容。

為指定文本添加Tags可以使用tag_add()方法:

 

1 from tkinter import *
2 root = Tk()
3 text = Text(root,width=30,height=10)
4 text.pack()
5 text.insert(INSERT,'I love python3.6')
6 text.tag_add("tag1","1.7","1.12","1.14")
7 text.tag_config("tag1",background="yellow",foreground="red")
8 mainloop()

 

執行結果:

如上,使用tag_config()方法可以設置Tags的樣式。下表列舉了tag_config()可以使用的選項。

如上,使用 tag_config() 方法可以設置 Tags 的樣式。下面羅列了 tag_config() 方法可以使用的選項:

選項 含義
background

①指定該Tag所描述的內容的背景顏色

②注意:bg並不是該選項的縮寫,在這里bg被解釋成bgstipple選項的縮寫

bgstipple

①指定一個位圖作為背景,並使用background選項指定的顏色填充

②只有設定了background選項,該選項才會生效

③默認的標准位圖有:'error', 'gray75', 'gray50', 'gray25', 'gray12', 'hourglass', 'info', 'questhead', 'question'和'warning'

borderwidth

①指定文本框的寬度

②默認值是0

③只有設定了relief選項該選項才會生效

④注意:該選項不能使用bd縮寫

fgstipple

①指定一個位圖作為前景色

②默認的標准位圖有:'error', 'gray75', 'gray50', 'gray25', 'gray12', 'hourglass', 'info', 'questhead', 'question'和'warning'

font ①指定該Tag所描述的內容使用的字體
foreground

①指定該Tag所描述的內容使用的前景色

②注意:fg並不是該選項的縮寫,在這里fg被解釋為fgstipple的縮寫

justify

①控制文本的對齊方式

②默認是LEFT(左對齊),還可以選擇RIGHT(右對齊)和CENTER(居中)

③注意:需要將Tag指向該行的第一個字符,該選項才能生效

Imargin1

①設置Tag指向的文本塊第一行的縮進

②默認值是0

③注意:需要將Tag指向該行的第一個字符或整個文本塊,該選項才能生效

Imargin2

①設置Tag指向的文本塊除了第一行其他行的縮進

②默認值是0

③注意:需要將Tag指向整個文本塊,該選項才能生效

offset

①設置Tag指向的文本相對於基線的偏移距離

②可以控制文本相對於基線是升高(正數值)或者降低(負數值)

③默認值是0

overstrike

①在Tag指定的文本范圍畫一條刪除線

②默認值是False

relief

①指定Tag對應范圍的文本的邊框樣式

②可以使用的值有:SUNKEN,RAISED,GROOVE,RIDGE或FLAT

③默認值是FLAT(沒有邊框)

margin

①設置Tag指向的文本塊右側的縮進

②默認值是0

spacing1

①設置Tag所描述的文本塊中每一行與上方的文本間隔

②注意:自動換行不算

③默認值是0

spacing2

①設置Tag所描述的文本塊中自動換行的各行間的空白間隔

②注意:換行符("\n")不算

③默認值是0

spacing3

①設置Tag所描述的文本塊中每一行與下方的文本間隔

②注意:自動換行不算

③默認值是0

tabs

①定制Tag所描述的文本塊中Tab按鍵的功能

②默認Tab被定義為8個字符的寬度

③你還可以定制多個制表位:tabs=('3c', '5c', '12c')表示前三個Tab的寬度分別為3cm,5cm,12cm,接着的Tab按照最后兩個的差值計算,即:19cm,26cm,33cm

④你應該注意到,它上邊'c'的含義是“厘米”而不是“字符”,還可以選擇的單位有"i"(英寸),"m"(毫米),"p"(DPI,大約是'1i'等於'72p')

⑤如果是一個整型值,則單位是像素

underline

①該選項設置為True的話,則Tag所描述的范圍內的文本將被畫上下划線

②默認值是False

wrap

①設置當一行文本的長度超過width選項設置的寬度時,是否自動換行。

②該選項的值可以是:NONE(不自動換行),CHAR(按字符自動換行)和WORD(按單詞自動換行)

如果對於一個范圍內容的文本加上多個Tags,並且相同的選項,那么新創建的Tag樣式會覆蓋比較舊的Tag:

 

1 from tkinter import *
2 root = Tk()
3 text = Text(root,width=30,height=10)
4 text.pack()
5 text.tag_config("tag1",background="yellow",foreground="red")
6 text.tag_config("tag2",foreground="blue")
7 #tag2中foreground將覆蓋tag1中的foreground,tag2中沒有background,所以用tag1的
8 text.insert(INSERT,'I love python3.6',("tag1","tag2"))
9 mainloop()

執行結果:

不過,這里可以使用tagraise()和tag_lower()方法來提高和降低某個Tag的優先級:

1 from tkinter import *
2 root = Tk()
3 text = Text(root,width=30,height=10)
4 text.pack()
5 text.tag_config("tag1",background="yellow",foreground="red")
6 text.tag_config("tag2",foreground="blue")
7 text.tag_lower("tag1")
8 text.insert(INSERT,'I love python3.6',("tag1","tag2"))
9 mainloop()

執行結果:

Tag還可以支持時間的綁定,綁定時間使用的是tag_bind()方法。下面舉個例子:讓文本(“python3.6”)與鼠標事件進行綁定,當鼠標進入該文本段的時候,鼠標樣式切換“arrow”狀態,離開文本段的時候切換回“xterm”形態。當觸發鼠標“左鍵單擊操作”時間的時候,使用默認瀏覽器打開綁定的鏈接:

 1 from tkinter import *
 2 root = Tk()
 3 text = Text(root,width=30,height=10)
 4 text.pack()
 5 text.insert(INSERT,'I love python3.6')
 6 text.tag_add("link","1.7","1.16")
 7 text.tag_config("link",foreground="blue",underline=True)
 8 def show_hand_cursor(event):
 9     text.config(cursor="arrow")
10 def show_arrow_cursor(event):
11     text.config(cursor="xterm")
12 def click(event):
13     webbrowser.open("http://www.baidu.com")
14 text.tag_bind("link","<Enter>",show_hand_cursor)
15 text.tag_bind("link","<Leave>",show_arrow_cursor)
16 text.tag_bind("link","<Button-1>",click)
17 mainloop()

執行結果:

 下面給大家介紹幾個比較實用的Text組件

第一個是判斷內容是否發生變化,例如做一個記事本,當用戶關閉的時候,程序需要檢查內容是否有改動,如果有,需要提醒用戶保存。下面的例子中,可以通過小燕Text組件中文本的MD5摘要來判斷內筒是否發生改變。

 1 from tkinter import *
 2 import hashlib
 3 root = Tk()
 4 text = Text(root,width=20,height=5)
 5 text.pack()
 6 text.insert(INSERT,"I love Python3.x")
 7 contents = text.get(1.0,END)
 8 def getSig(contents):
 9     m = hashlib.md5(contents.encode())
10     return m.digest()
11 sig = getSig(contents) 
12 def check():
13     contents = text.get(1.0,END)
14     if sig != getSig(contents):
15         print("內容沒有保存")
16     else:
17         print("文件沒有改動")
18 Button(root,text="檢查",command=check).pack()
19 mainloop()

 執行結果:

第二個是查找操作,是使用search()方法可以搜索Text組件中的內容,可以提供一個確切的目標進行搜索(默認),也可以使用Tcl格式的正則表達式進行搜索需要設置regexp選項為True(:):

 1 from tkinter import*
 2 root = Tk()
 3 text = Text(root,width=30,height=5)
 4 text.pack()
 5 text.insert(INSERT,"I love python3.6")
 6 #將任何格式的索引號統一為元組(行,列)的格式輸出
 7 def getIndex(text,index):
 8     return tuple(map(int,str.split(text.index(index),".")))
 9 start = 1.0
10 while True:
11     pos = text.search("o",start,stopindex=END)
12     if not pos:
13         break
14     print("找到了,位置是:",getIndex(text,pos))
15     start = pos + "+1c" #將start指向下一個字符
16 mainloop()

執行結果:

找到了,位置是: (1, 3)
找到了,位置是: (1, 11)
這里第一是找出“o"的位置,然后以"o"為起點,繼續找第二個位置,直到找完
注意:這里如果忽略stopindex選項,表示知道文本的末尾結束搜索。設置backwards選項為True,則是修改搜索的方向(變為向后搜索,那么start遍歷應該設置為END,stopindex選項設置為1.0,最后+1c設置為-1c )
最后,Text組件還支持“恢復”和“撤銷”操作,這使得Text組件顯得相當高大上。通過設置undo選項為True,可以開啟Text組件的撤銷功能,然后利用editundo可以開啟實現撤銷操作,用editredo()方法可以實現恢復操作。
 1 from tkinter import *
 2 import hashlib
 3 root = Tk()
 4 text = Text(root,width=20,height=5)
 5 text.pack()
 6 text.insert(INSERT,"I love Python3.x")
 7 def show():
 8     text.edit_undo()
 9 Button(root,text="撤銷",command=show).pack()
10 mainloop()
執行結果:

點擊一次撤銷后,插入進去的數據已經沒有 了

這是因為Text組件內部有一個棧專門用於記錄每次變動,所以每次“撤銷”操作就是一次彈棧操作,“恢復”就是再次壓棧。

默認情況下,每次完整的操作都會放入棧中。但怎么樣算是一次完整的操作了?Tkinter覺得每次焦點切換、用戶按下回車鍵、刪除/插入操作的轉換等之前的操作算是一次完整的操作。也就是說,你連續輸入“python”的話,一次“撤銷”操作就會將所有內容刪除。

但是我們可以自定義,做法就是先將autoseparators選項設置為False(因為這個選項是讓Tkinter在人為一次完成的操作結束后自動插入“分隔符”,然后綁定鍵盤事件,每次有輸入就用edit_separator()方法人為插入一個“分隔符”:

 1 from tkinter import *
 2 import hashlib
 3 root = Tk()
 4 text = Text(root,width=20,height=5,autoseparators=False,undo=True,maxundo=10) 5 text.pack()
 6 def callback():
 7     text.edit_separator()
 8 text.bind("<Key>",callback)
 9 text.insert(INSERT,"I love Python3.x")
10 def show():
11     text.edit_undo()
12 Button(root,text="撤銷",command=show).pack()
13 mainloop()

 

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM