1. 程式人生 > >《零基礎入門學習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組價構成的。

我們舉個例子來演示一下:

import tkinter as tk

root = tk.Tk()

text = tk.Text(root, width = 30, heigh = 2)
text.pack()

text.insert("insert", "I love \n")
text.insert("end", "Python.com")

root.mainloop()

執行一下:

我們可以對這個文字內容進行任意的操作。

Text 組價不僅支援插入和編輯文字,還支援插入 image 物件,或者前面介紹的元件,例如說你可以插入一個按鈕

import tkinter as tk

root = tk.Tk()

text = tk.Text(root, width = 30, heigh = 5)
text.pack()

text.insert("insert", "I love \n")
text.insert("end", "Python.com!")

def show():
        print("哪裡不會點哪裡")

b1 = tk.Button(text, text = "點我啊", command = show)
text.window_create("insert", window = b1)

root.mainloop()

接下來插入圖片試一下:


import tkinter as tk

root = tk.Tk()

text = tk.Text(root, width = 30, heigh = 10)
text.pack()

photo = tk.PhotoImage(file = 'logo.gif')

def show():
        text.image_create("end", image = photo)
        

b1 = tk.Button(text, text = "點我啊", command = show)
text.window_create("insert", window = b1)

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 解釋為已有內容的末尾的下一個位置。

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


import tkinter as tk

root = tk.Tk()

text = tk.Text(root, width = 30, heigh = 3)
text.pack()

text.insert("insert", "I love Python")
print(text.get("1.2", 1.6))

root.mainloop()

使用 index() 方法可以將所有支援的“索引”格式轉換為“行/列”格式的索引號。

"line.end"

行號加上字串 ".end" 的格式表示為該行最後一個字元的位置:

text.insert("insert", "I love Python")
print(text.get("1.2", "1.end"))
>>>
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 的文字的最後一個字元之後)語法表示標籤的範圍。

"%s.first" % tagname
"%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 或格式化操作來建立一個表示式字串。下邊例子演示瞭如何刪除插入游標前邊的一個字元:

def backspace(event):
    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 事實上就是索引,用於表示位置:

import tkinter as tk

root = tk.Tk()

text = tk.Text(root, width = 30, heigh = 3)
text.pack()

text.insert("insert", "I love Python")
text.mark_set("here", "1.2")
text.insert("here", "插")

root.mainloop()

 

例2,如果 Mark 前邊的內容發生改變,那麼 Mark 的位置也會跟著移動(說白了就是 Mark 會“記住”它後邊的那貨~):

text.insert("insert", "I love Python")
text.mark_set("here", "1.2")
text.insert("here", "插")
text.insert("here", "入")

例3,如果 Mark 周圍的文字被刪除了,Mark 仍然還在噢(只是它後邊的那貨被刪除了,所以它六神無主,只能初始化為 "1.0"): 

text.insert("insert", "I love Python")
text.mark_set("here", "1.2")
text.insert("here", "插")

text.delete("1.0", "end")
text.insert("here", "入")



例4,只有 mark_unset() 方法可以解除 Mark 的封印:

text.insert("insert", "I love Python")
text.mark_set("here", "1.2")
text.insert("here", "插")

text.mark_unset("here")

text.delete("1.0", "end")
text.insert("here", "入")



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

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

例5(對比例2):

text.insert("insert", "I love Python")

text.mark_set("here", "1.2")
text.mark_gravity("here", "left")  #預設是 "right"

text.insert("here", "插")
text.insert("here", "入")

由於Text 元件的功能實在太強大,內容較多,剩下的下節課繼續講解。