2020年9月12日星期六

69 《零基礎入門學習Python》筆記 第069講:GUI的終極選擇:Tkinter6

《零基礎入門學習Python》第069講:GUI的終極選擇:Tkinter6


前面我們已經學習了Tkinter 的好幾個組件。繪製單行文本我們當然知道要使用Label 組件,多行選項我們使用Listbox 組件,輸入框用Entry 組件,Button 就是按鈕,Radiobutton 和Checkbutton 分別對應單选和多選的情況,然後呢,有多個組件,我們還可以使用Frame 和LabelFrame 把它們構成一個框架,之後我們還學習了兩個會滾的組件:Scrollbar 和Scale,Scrollbar 就是滾動條,Scale 就是提供一個範圍,讓用戶在這個範圍內選擇一個確切的值。
今天我們繼續學習一個新的組件:Text組件。這個組件主要是用於顯示和處理多行文本,那麼在tkinter的所有組件中,Text 組件顯得異常強大和靈活,適用於多種任務。雖然說這個組件的主要任務是用於顯示多行文本,但是它常常被用於當做簡單的文本處理器、文本編輯器或者網頁瀏覽器來使用,例如我們的IDLE的輸入框,就是Text組價構成的。
我們舉個例子來演示一下:
  1. import tkinter as tk
  2. root = tk.Tk()
  3. text = tk.Text(root, width = 30, heigh = 2)
  4. text.pack()
  5. text.insert("insert", "I love \n")
  6. text.insert("end", "Python.com")
  7. root.mainloop()
運行一下:
我們可以對這個文本內容進行任意的操作。
Text 組價不僅支持插入和編輯文本,還支持插入image 對象,或者前面介紹的組件,例如說你可以插入一個按鈕
  1. import tkinter as tk
  2. root = tk.Tk()
  3. text = tk.Text(root, width = 30, heigh = 5)
  4. text.pack()
  5. text.insert("insert", "I love \n")
  6. text.insert("end", "Python.com!")
  7. def show():
  8. print("哪里不会点哪里")
  9. b1 = tk.Button(text, text = "点我啊", command = show)
  10. text.window_create("insert", window = b1)
  11. root.mainloop()
接下來插入圖片試一下:
  1. import tkinter as tk
  2. root = tk.Tk()
  3. text = tk.Text(root, width = 30, heigh = 10)
  4. text.pack()
  5. photo = tk.PhotoImage(file = 'logo.gif')
  6. def show():
  7. text.image_create("end", image = photo)
  8. b1 = tk.Button(text, text = "点我啊", command = show)
  9. text.window_create("insert", window = b1)
  10. root.mainloop()
看到這裡,你是不是覺得Text組件很強大呢?其實更牛的東西還在後頭。我們接著來:

Indexes 用法

Indexes(索引)是用來指向Text 組件中文本的位置,跟Python 的序列索引一樣,Text 組件索引也是對應實際字符之間的位置。
Tkinter 提供一系列不同的索引類型:
  • "line.column"(行/列)
  • "line.end"(某一行的末尾)
  • "insert"
  • "current"
  • "end"
  • user-defined marks
  • user-defined tags("tag.first","tag.last")
  • selection(SEL_FIRST,SEL_LAST)
  • window coordinate("@x,y")
  • embedded object name(window,images)
  • expressions
下邊我們逐個給大家講解:

"line.column"

由於我們的Text組件是支持多行文本的,所以我們現在從一個一維空間變成了二維空間,我們就可以用行和列來定位一個位置。
"%d.%d" % (line, column)
行/列是最基礎的索引方式,它們將索引位置的行號和列號以字符串的形式表示出來(中間以"." 分隔,例如"1.0")。需要注意的是,行號以1 開始,列號則以0 開始。
指定超出現有文本的最後一行的行號,或超出一行中列數的列號都不會引發錯誤。對於這樣的指定,Tkinter 解釋為已有內容的末尾的下一個位置。
需要注意的是,使用行/列的索引方式看起來像是浮點值。其實不只像而已,你在需要指定索引的時候使用浮點值代替也是可以的:
  1. import tkinter as tk
  2. root = tk.Tk()
  3. text = tk.Text(root, width = 30, heigh = 3)
  4. text.pack()
  5. text.insert("insert", "I love Python")
  6. print(text.get("1.2", 1.6))
  7. root.mainloop()
使用index() 方法可以將所有支持的“索引”格式轉換為“行/列”格式的索引號。

"line.end"

行號加上字符串".end" 的格式表示為該行最後一個字符的位置:
  1. text.insert("insert", "I love Python")
  2. print(text.get("1.2", "1.end"))
  1. >>>
  2. love Python
"insert"
對應插入光標的位置。
"current"
對應與鼠標坐標最接近的位置。不過,如果你緊按鼠標任何一個按鈕,它會直到你鬆開它才響應。
 "end"
對應Text 組件的文本緩衝區最後一個字符的下一個位置。
user-defined marks

user-defined marks是對Text組件中位置的命名。"insert"和"current"是兩個預先命名好的marks,除此之外你可以自定義marks(請參考下方【Marks用法】)。

User-defined tags

User-defined tags代表可以分配給Text組件的特殊事件綁定和風格(請參考下節課的【Tags用法】)。

你可以使用"tag.first"(使用tag的文本的第一個字符之前)和"tag.last"(使用tag的文本的最後一個字符之後)語法表示標籤的範圍。
  1. "%s.first" % tagname
  2. "%s.last" % tagname
如果查無此tag,那麼Tkinter會拋出一個TclError異常。

selection(SEL_FIRST,SEL_LAST)

selection是一個名為SEL(或"sel")的特殊tag,表示當前被選中的範圍,你可以使用SEL_FIRST到SEL_LAST來表示這個範圍。如果沒有選中的內容,那麼Tkinter會拋出一個TclError異常。

window coordinate("@x,y")

你還可以使用窗口坐標作為索引。例如在一個事件綁定中,你可以使用以下代碼找到最接近鼠標位置的字符:
"@%d,%d" % (event.x, event.y)
embedded object name(window,images)

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

expressions

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

具體表達式實現如下:
表達式
含義
"+ count chars"1.將索引向前(->)移動count個字符
2.可以越過換行符,但不能超過END的位置
"- count chars"1.將索引向後(<-)移動count個字符
2.可以越過換行符,但不能超過"1.0"的位置
"+ count lines"1.將索引向前(->)移動count行
2.索引會盡量保持與移動前在同一列上,但如果移動後的那一行字符太少,將移動到該行的末尾
"- count lines"1.將索引向後(<-)移動count行
2.索引會盡量保持與移動前在同一列上,但如果移動後的那一行字符太少,將移動到該行的末尾
" linestart"1.將索引移動到當前索引所在行的起始位置
2.注意,使用該表達式前邊必須有一個空格隔開
" lineend"1.將索引移動到當前索引所在行的末尾
2.注意,使用該表達式前邊必須有一個空格隔開
" wordstart"1.將索引移動到當前索引指向的單詞的開頭
2.單詞的定義是一系列字母、數字、下劃線或任何非空白字符的組合
3.注意,使用該表達式前邊必須有一個空格隔開
" wordend"1.將索引移動到當前索引指向的單詞的末尾
2.單詞的定義是一系列字母、數字、下劃線或任何非空白字符的組合
3.注意,使用該表達式前邊必須有一個空格隔開
TIPS:只要結果不產生歧義,關鍵字可以被縮寫,空格也可以省略。例如:"+ 5 chars"可以簡寫成"+5c"

在實現中,為了確保表達式為普通字符串,你可以使用str或格式化操作來創建一個表達式字符串。下邊例子演示瞭如何刪除插入光標前邊的一個字符:
  1. def backspace(event):
  2. event.widget.delete("%s-1c" % "insert", "insert")

Marks 用法

Marks(標記)通常是嵌入到Text 組件文本中的不可見對象。事實上Marks 是指定字符間的位置,並跟隨相應的字符一起移動。Marks 有"insert","current" 和user-defined marks(用戶自定義的Marks)。其中,"insert" 和"current" 是Tkinter 預定義的特殊Marks,它們不能夠被刪除。
"insert"用於指定當前插入光標的位置,Tkinter會在該位置繪製一個閃爍的光標(因此並不是所有的Marks都不可見)。

 "current"用於指定與鼠標坐標最接近的位置。不過,如果你緊按鼠標任何一個按鈕,它會直到你鬆開它才響應。

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

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

如果有做相關練習的,應該會被Mark的很多特性所疑惑,在準備這個內容的時候也很是迷惑,找了不知多少文檔......最後總結為下邊幾個例子講解:

例1 ,Mark事實上就是索引,用於表示位置:
  1. import tkinter as tk
  2. root = tk.Tk()
  3. text = tk.Text(root, width = 30, heigh = 3)
  4. text.pack()
  5. text.insert("insert", "I love Python")
  6. text.mark_set("here", "1.2")
  7. text.insert("here", "插")
  8. root.mainloop()
 
例2,如果Mark 前邊的內容髮生改變,那麼Mark 的位置也會跟著移動(說白了就是Mark 會“記住”它後邊的那貨~):
  1. text.insert("insert", "I love Python")
  2. text.mark_set("here", "1.2")
  3. text.insert("here", "插")
  4. text.insert("here", "入")
例3,如果Mark 周圍的文本被刪除了,Mark 仍然還在噢(只是它後邊的那貨被刪除了,所以它六神無主,只能初始化為"1.0"): 
  1. text.insert("insert", "I love Python")
  2. text.mark_set("here", "1.2")
  3. text.insert("here", "插")
  4. text.delete("1.0", "end")
  5. text.insert("here", "入")


例4,只有mark_unset() 方法可以解除Mark 的封印:
  1. text.insert("insert", "I love Python")
  2. text.mark_set("here", "1.2")
  3. text.insert("here", "插")
  4. text.mark_unset("here")
  5. text.delete("1.0", "end")
  6. text.insert("here", "入")


看,其實也沒有那麼難嘛~

好,講最後一點,我們看到了,默認插入內容到Mark,是插入到它的左側(就是說插入一個字符的話,Mark向後移動了一個字符的位置) 。那能不能插入到Mark的右側呢?其實是可以的,通過mark_gravity()方法就可以實現。

例5(對比例2):
  1. text.insert("insert", "I love Python")
  2. text.mark_set("here", "1.2")
  3. text.mark_gravity("here", "left") #默认是 "right"
  4. text.insert("here", "插")
  5. text.insert("here", "入")
由於Text 組件的功能實在太強大,內容較多,剩下的下節課繼續講解。


0 留言:

發佈留言