介紹
Tkinter 模組(Tk 介面)是 Python 的標準 Tk GUI 工具包的介面 .Tk 和 Tkinter 可以在大多數的 Unix 平臺下使用,同樣可以應用在 Windows 和 Macintosh 系統裡。Tk8.0 的後續版本可以實現本地視窗風格,並良好地執行在絕大多數平臺中。
Tkinter 是 Python 的標準 GUI 庫。Python 使用 Tkinter 可以快速的建立 GUI 應用程式。
由於 Tkinter 是內建到 python 的安裝包中、只要安裝好 Python 之後就能 import Tkinter 庫、而且 IDLE 也是用 Tkinter 編寫而成、對於簡單的圖形介面 Tkinter 還是能應付自如。
注意:Python3.x 版本使用的庫名為 tkinter,即首寫字母 T 為小寫。
模組
匯入方式
import tkinter
驗證模組是否已安裝
終端中執行命令:python -m tkinter
,執行後介面會彈出一個 tk 小視窗,表示安裝成功,而且告訴你 Tcl/Tk 的版本號,通過這個版本號,你就可以參考對應的 Tcl/Tk 文件了。
API 使用
主視窗
建立 GUI 介面,作為根視窗:
# 建立主視窗
root = tk.Tk()
root.title("tk Root") # 設定視窗名稱
root.geometry('200x200') # 設定視窗大小
執行視窗
# 執行
root.mainloop()
元件列表介紹
類 | 名稱 | 簡介 |
---|---|---|
Toplevel | 頂層 | 容器類,為其他元件提供單獨容器 |
Button | 按鈕 | 按鈕元件 |
Canvas | 畫布 | 提供繪圖功能,包括:直線,矩形,橢圓,多邊形,點陣圖等 |
Checkbutton | 核取方塊 | 可選的核取方塊 |
Entry | 單行輸入框 | 可輸入內容 |
Frame | 容器 | 裝載其它GUI元件 |
Label | 標籤 | 顯示不可編輯的文字或圖示 |
LabelFrame | 容器 | 容器元件,類似Frame支援新增標題 |
Listbox | 列表框 | 列出多個選項,供選擇 |
Menu | 選單 | 選單元件 |
Menubutton | 選單按鈕 | 包含選單的按鈕(下拉式,層疊式) |
OptionMeny | 選單按鈕 | Menubutton的子類,可通過按鈕開啟一個選單 |
Message | 訊息框 | 類似標籤,但可以顯示多行文字 |
PanedWindow | 分割槽視窗 | 該容器會被劃分成多個區域,每新增一個元件佔一個區域,使用者可以拖動分割線改變各區域大小 |
Radiobutton | 單選鈕 | 供使用者點邊的單選妞 |
Scale | 滑動條 | 拖動滑動塊可設定起始值和結束值,可顯示當前位置的精確值 |
Spinbox | 微調選擇器 | 可通過該元件的向上、向下箭頭選擇不同的值 |
Scrollbar | 滾動條 | 為元件提供滾動功能 |
Text | 多行文字框 | 顯示多行文字 |
Label 標籤
屬性說明:
width, height=寬高 font(name,size)=字型 image=影像(只支援GIF格式)
fg(foreground)=前景色 bg(background)=背景色 justify(left|center|right)=對齊方式
# 設定 label 屬性
L = tk.Label(root, # 視窗
text='展示標籤!', # 描述
bg='green', # 背景
borderwidth=5, # 邊界寬度
relief="solid", # 指定元件 3D 效果
justify="right", # 字型對齊方式
font=('微軟雅黑', 12), # 字型
width=15, height=2) # 寬高
# 放置 label 控制元件在視窗中的位置
L.pack(side='right') # 上top下bottom 左left右right
# 配置GIF圖片方式
gifpath = r"D:\xxx\www.gif"
photo = tk.PhotoImage(file=gifpath) # 例項化圖片物件
lab = tk.Label(image=photo) # 設定圖片標籤
lab.pack()
Button 按鈕
# 定義空字串變數,用於標籤屬性中接收資料
var = tk.StringVar()
# 設定 label 標籤屬性
L = tk.Label(root, # 視窗
# text='展示標籤!', # 描述
textvariable=var, # 接收外部傳參
bg='green', # 背景
font=('微軟雅黑', 12), # 字型
width=15, height=2) # 寬高
# 放置 label 位置
L.pack() # 上下 左left右right
on_func = False # 定義一個開關
# 按鈕事件
def func():
global on_func
if on_func:
on_func = False
var.set('')
else:
on_func = True
var.set('要顯示內容')
# 設定 button 按鈕屬性
B = tk.Button(root, text='按鈕', width=15, height=2,
command=func) # 設定按鈕事件,函式
B.pack()
Options 屬性選項
元件中的屬性,可以通過 Options 設定元件對應的屬性,從而控制元件的各種狀態。比如:寬度、高度、背景色等等。
有三種方式設定 Options 選項,在各種 GUI 元件中用法都一致。
- 建立物件時,使用命名引數(也叫關鍵字引數):
fred = Button(width=15, height=2, bg="blue")
- 建立物件後,使用字典索引方式:
fred['fg'] = "red"
fred['bg'] = "blue"
- 建立物件後,使用
config()
方式:
fred.config(width=15, height=2, bg="blue")
- 屬性選項列表:
屬性名 | 簡介 |
---|---|
activebackground | 指定元件處於啟用狀態時的背景色 |
activeforeground | 指定元件處於啟用狀態時的前景色 |
disabledforeground | 指定元件處於禁用狀態時的前景色 |
anchor | 指定元件內的字元在元件中顯示位置,選項值(N,NE,E,SE,S,SW,W,NW,CENTER) |
background | 元件正常的背景色(bg) |
foreground | 元件正常的前景色(fg) |
bitmap | 指定在元件上顯示該選項指定的點陣圖,點陣圖的顯示方式受anchor、justify影響。如果同時指定bitmap和text,那麼bitmap覆蓋文字;如果同時指定bitmap和image,那麼image覆蓋bitmap。 |
relief | 元件的3D效果,支援: raised(凸起),sunken(凹陷),flat(平坦),ridge(隆起),solid(實心),groove(凹槽) |
borderwidth | 指定元件正常顯示的3D邊框寬度 |
cursor | 指定游標在元件上的樣式 |
command | 指定元件關聯的命令方法。該方法在元件離開元件時觸發 |
font | 元件上顯示的文字字型 |
highlightbackground | 指定元件在高亮狀態下的背景色 |
highlightcolor | 指定元件在高亮狀態下的前景色 |
highlightthickness | 指定元件在高亮狀態下的周圍方形區域的寬度 |
state | 元件的當前狀態,支援:NORMAL(正常),DISABLE(禁用) |
height | 元件的高度 |
width | 元件的寬度 |
wraplength | 對於能支援字元換行的元件,該選項指定每行顯示的最大字元數,超過設定自動換行 |
image | 元件中顯示的圖片 |
justify | 元件內部內容對齊方式,支援(小寫):LEFT(左對齊),CENTER(居中),RIGHT(右對齊) |
padx | 元件內部在水平方向上兩邊的空白 |
pady | 元件內部在垂直方向上兩邊的空白 |
takefocus | 指定元件在鍵盤遍歷(Tab或Shift+Tab)時是否接收焦點,將選項設為1:接收焦點;設為0:不接受焦點 |
text | 元件顯示的文字 |
textvariable | 指定一個變數名,元件負責顯示該變數值轉換得到的字串 |
underline | 指定元件文字的第幾個字元新增下劃線,該選項相當於為元件繫結了快捷鍵 |
xscrollcommand | 通常用於將元件的水平滾動改變與水平滾動條的 set 方法關聯,從而讓元件的水平滾動改變傳遞到水平滾動條 |
yscrollcommand | 通常用於將元件的垂直滾動改變與垂直滾動條的 set 方法關聯,從而讓元件的垂直滾動改變傳遞到垂直滾動條 |
文字框
Entry 單行文字框
Entry 用來接收一行字串的控制元件,如果使用者輸入的內容長度超過 Entry 控制元件的寬度時,文字會自動換行。
簡單示例:
def login():
print('名稱:'+entry1.get()) # 接收文字框的內容
labe = tk.Label(root, text="名稱:")
labe.pack()
v1 = tk.StringVar() # 設定空字串變數,屬性value='可設定預設值'
# 單行文字框
# show屬性可將輸入的內容轉為指定字元方式顯示,比如輸入密碼
entry1 = tk.Entry(root, textvariable=v1, show='*')
entry1.pack()
v1.set('設定初始值...') # 方式二:單獨設定預設值
tk.Button(root, text='傳送文字中內容', command=login).pack()
Text 多行文字框
主要用來顯示多行文字,還可以顯示網頁連結、圖片、HTML、CSS樣式表、新增元件等等。
wrap=換行方式,word:單詞換行
undo,True:開啟撤銷功能, False:不開啟
示例:
''' Text 多行文字框 '''
tk.Label(root, text='文字框:', width=30).pack(anchor='w')
# 建立多行文字
tex = tk.Text(root, width=40, height=12)
tex.pack()
- insert(index, 'str') 插入屬性
index:位置,可數字表示(行從1起,列從0起),或INSERT(開始)、END(結尾)
str:需要插入的內容
規則:不包頭,包尾
tex.insert('insert', 'ABCD\nEFG') # 在第一行第0列位置插入內容
tex.insert(2.2, '12345') # 在第二行第3列位置插入內容
'''結果:
ABCD
EF12345G
'''
- get(insert, end) 獲取內容屬性
insert:起始位置,int型別,用1.0表示(行從1起,列從0起);
end:結尾,str型別或 int型別,用1.0表示(行從1起,列從0起);
tex.get(3.2, 3.7) # 指定範圍內
tex.get(3.2, 'end') # 指定起始位置至結尾
- 在文字框中放入圖片:
gifpath1 = r"D:\xxxx\www.gif"
photo1 = tk.PhotoImage(file=gifpath1)
tex.image_create('end', image=photo1) # 在結尾放入圖片
文字框屬性:
background, bd, bg, borderwidth, cursor,exportselection, fg, font, foreground, ighlightbackground,
highlightcolor, highlightthickness, insertbackground,insertborderwidth, insertofftime, insertontime,
insertwidth,invalidcommand, invcmd, justify, relief, selectbackground,selectborderwidth,
electforeground, show, state, takefocus,textvariable, validate, validatecommand, vcmd, width,xscrollcommand
選擇框
Radiobutton 單選框
value: 定義單選按鈕返回的內容
''' 單選按鈕 '''
def confirm():
messagebox.showinfo('測試', '選擇的內容:' + var.get())
var = tk.StringVar()
var.set("J")
tk.Label(root, text='單選: ', width=10).pack(anchor='w')
radio1 = tk.Radiobutton(root, text='Python', value='P', variable=var)
radio2 = tk.Radiobutton(root, text='Java', value='J', variable=var)
radio1.pack(anchor='w'); radio2.pack(anchor='w')
tk.Button(root, text='確認', command=confirm).pack()
Checkbutton 多選框
onvalue=1 # 1 表示預設選狀態,0 表示不選 offvalue=0 # 未選擇的返回值
def check():
if code.get() == 1 and vide.get() == 1:
messagebox.showinfo('多選', '選擇:python, java')
elif vide.get() == 1:
messagebox.showinfo('多選', '選擇:java')
elif code.get() == 1:
messagebox.showinfo('多選', '選擇:python')
else:
messagebox.showinfo('多選', '都沒選擇!')
tk.Label(root, text='多選:', width=10).pack(anchor='w')
code = tk.IntVar(); vide = tk.IntVar() # 接收int型別引數
check1 = tk.Checkbutton(root, text='python', onvalue=1, offvalue=0, variable=code)
check2 = tk.Checkbutton(root, text='Java', onvalue=1, offvalue=0, variable=vide)
check1.pack(anchor='w'); check2.pack(anchor='w')
tk.Button(root, text='多選確認', command=check).pack()
選擇框屬性:
activebackground, activeforeground, anchor,background, bd, bg, bitmap, borderwidth,
command, cursor,disabledforeground, fg, font, foreground, height,highlightbackground,
highlightcolor, highlightthickness, image,indicatoron, justify, offvalue, onvalue, padx, pady,
relief,selectcolor, selectimage, state, takefocus, text, textvariable,underline, variable, width, wraplength
通用訊息彈窗
messagebox 訊息彈框
Messagebox 用於顯示彈出訊息。Messagebox主要提供了7種訊息提示,如:showinfo()、showerror()、showwarning()、askquestion()、askokcancel()、askyesno()、askretyrcancel()。
匯入方式:
from tkinter import messagebox
訊息對話方塊函式列表:
返回值:選擇項
函式 | 說明 |
---|---|
showinfo(title, message, **options) | 訊息提示框 |
showerror(title, message, **options) | 錯誤提示框 |
showwarning(title, message, **options) | 警告提示框 |
askquestion(title, message, **options) | 疑問提示框 |
askokcancel(title, message, **options) | 確定/取消 |
askyesno(title, message, **options) | yes/No |
askretrycancel(title, message, **options) | 重試/取消 |
簡單示例:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.title("TK title")
root.geometry("500x1000+100+200")
def msg1():
messagebox.showinfo('information', 'Hi! You got a prompt.')
messagebox.showerror('error', 'Something went wrong!')
messagebox.showwarning('warning', 'accept T&C')
messagebox.askquestion('Ask Question', 'Do you want to continue?')
messagebox.askokcancel('Ok Cancel', 'Are You sure?')
messagebox.askyesno('Yes|No', 'Do you want to proceed?')
messagebox.askretrycancel('retry', 'Failed! want to try again?')
tk.Button(root, text='Click Me', command=msg1).pack(pady=50)
canvas 畫布
canvas 畫布是一個矩形區域,可以放置圖形、影像、元件等等。
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
# 代表父類的定義,不是父類物件
super().__init__(master)
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
self.canvas = tk.Canvas(self, width=300, height=200, bg='green')
self.canvas.pack()
# 畫一條直線
self.canvas.create_line(10,10,30,20,40,50)
# 畫一個矩形
self.canvas.create_rectangle(50,50,100,100)
# 畫一個圓
self.canvas.create_oval(50,50,100,100)
# 加圖片
path = "D:\wangxin_m\selenium_py36\gui_tkinter\www.gif"
global photo
photo = tk.PhotoImage(file=path)
self.canvas.create_image(110,300, image=photo)
if __name__ == '__main__':
root = tk.Tk()
root.title('畫布練習')
root.geometry('500x200+200+200')
app = Application(master=root)
root.mainloop()
佈局管理
一個 GUI 應用程式必然有大量的元件,tkinter提供了佈局管理器幫助我們組織、管理在父元件中子元件的佈局方式。提供了三種管理器:pack、grid、place。
grid 表格佈局
採用表格結構組織元件;子元件的位置由行和列的單元格來確定,並且可以跨行和跨列,從而實現複雜的佈局。
grid()方法提供的選項:
選項 | 說明 |
---|---|
column | 單元格的列號(從0開始) |
columnspan | 跨列 |
row | 單元格的行號(從0開始) |
rowspan | 跨行 |
ipadx,ipady | 設定子元件之間的間隔 |
padx,pady | 並列的元件之間的間隔 |
sticky | 元件緊貼所在單元格的某一角,對應對應東南西北及4個角 |
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
# 代表父類的定義,不是父類物件
super().__init__(master)
self.master = master
self.pack()
self.gridWidget()
def gridWidget(self):
self.labY = tk.Label(self, text='使用者名稱')
self.labP = tk.Label(self, text='iPhone')
self.enrY = tk.Entry(self)
self.enrP = tk.Entry(self)
# 設定控制元件位置
self.labY.grid(row=0, column=0) # row=0, column=0 表示:第1行第1列位置
self.enrY.grid(row=0, column=1)
self.labP.grid(row=1, column=0)
self.enrP.grid(row=1, column=1)
tk.Button(self, text='登入').grid(row=2, column=0, sticky='w')
tk.Button(self, text='取消').grid(row=2, column=1, sticky='e')
# 跨行,多行文字框
self.text = tk.Text(self, width=28, height=3)
self.text.grid(row=3, column=0, columnspan=2)
if __name__ == '__main__':
root = tk.Tk()
root.title('畫布練習')
app = Application(master=root)
root.mainloop()
計算器佈局示例:
class Application(tk.Frame):
def __init__(self, master=None):
# 代表父類的定義,不是父類物件
super().__init__(master)
self.master = master
self.pack()
self.jsqWidget()
def jsqWidget(self):
btnText = (("MC", "M+", "M-", "MR"), ("C", "±", "/", "*"),
(7,8,9,"-"),(4,5,6,"+"),(1,2,3,"="), (0, ".") )
# 顯示框,第一行
tk.Entry(self).grid(row=0, column=0, columnspan=4, pady=10)
# 按鈕控制元件佈局
for rindx, r in enumerate(btnText):
for cindx, c in enumerate(r):
if c == "=":
but_d = tk.Button(self, text=c, width=3)
but_d.grid(row=rindx+1, column=cindx, rowspan=2, sticky='nsWE')
elif c == 0:
but_0 = tk.Button(self, text=c, width=3)
but_0.grid(row=rindx+1, column=cindx, columnspan=2, sticky='nsWE')
elif c == '.':
but_d = tk.Button(self, text=c, width=3)
but_d.grid(row=rindx+1, column=cindx+1, sticky='nsWE')
else:
tk.Button(self, text=c, width=3).grid(row=rindx+1, column=cindx, sticky='nsWE')
pack 佈局
按照元件的建立順序將子元件新增到父元件中,按照“垂直”或者“水平”的方向自然排序。預設在父元件中自頂向下垂直新增元件。
pack()方法提供選項:
選項 | 說明 |
---|---|
expand | 當值為"YES"時,side選項無效,元件顯示在父元件中心位置,若fill選項為"both",則填充父元件的剩餘空間;'yes'或自然數、'no'或0(預設) |
fill | 填充x或y方向的空間,x=水平,y=垂直,both=兩邊填充;當屬性side='top'或'bottom'時,填充x方向;當屬性side='left'或'right'時,填充y方向;當expand選項為'yes'時,填充父元件的剩餘空間 |
ipadx,ipady | 設定子元件之間的間隔 |
padx,pady | 與之並列的元件之間的間隔 |
side | 定義停靠父元件的那個位置(left'、'right'、'top'、'bottom') |
before | 將本元件於所選元件物件之前pack,類似於先建立本元件選定的元件 |
after | 將本元件與選擇元件物件之後pack,類似先建立選定元件後再建立本元件 |
anchor | 對齊方式(n,s,w,e,nw,sw,se,ne,center) |
in_ | 將本元件所選元件物件的子元件,類似於指定本元件的masster為選定元件 |
示例:
root = tk.Tk()
root.title('畫布練習')
root.geometry("700x220")
# Frame 畫布區域,用於放置子元件
f1 = tk.Frame(root, bg='blue'); f1.pack()
f2 = tk.Frame(root, bg='yellow'); f2.pack()
btnText = ["A", "B", "C", "D"]
for t in btnText:
tk.Button(f1, text=t).pack(side='left', padx="10")
for i in range(1, 10):
tk.Label(f2, text=i, width=2, height=3, borderwidth=1, relief="raised",
bg="red").pack(side="left", padx=4)
root.mainloop()
place 佈局
通過座標精確控制元件的位置,適用於一些佈局更加靈活的場景。
place()方法選項:
選項 | 說明 | 取值範圍 |
---|---|---|
x,y | 元件左上角的絕對座標(相對於視窗) | 非負整數,x和y選項用於設定偏移(畫素),如果同時設定relx(rely) 和x(y),那麼place將優先計算relx和rely,然後在實現x和y指定的偏移值 |
relx,rely | 元件左上角的座標(相對於父視窗) | 相對父元件位置,0為最左邊,0.5為中間,1位最右邊 |
width,height | 元件的寬度和高度 | 正整數 |
relwidth,relheight | 元件的寬度和高度(相對於父視窗) | 與relx,rely類似,但是相對於父元件的尺寸 |
anchor | 對齊方式 | n,s,w,e,nw,sw,se,ne,center |
示例:
root = tk.Tk()
root.title('畫布練習')
root.geometry("500x300")
# Frame 畫布區域,用於放置子元件
f1 = tk.Frame(root, width=200, height=200, bg='blue'); f1.place(x=20, y=20)
tk.Button(root, text='root位置').place(relx=0.1, relwidth=0.3, relheight=0.2)
tk.Button(f1, text='f1位置').place(relx=0.2, rely=0.5)
root.mainloop()
事件處理
一個 GUI 應用整個生命週期都處在一個訊息迴圈(eventloop)中。它等待事件的發生,並作出相應的處理。
tkinter 提供了用以處理相關事件的機制,處理函式可被繫結給各個空間的各個事件。
widget.bind(event,handler)
如果相關事件發生, handler 函式會觸發,事件物件 event 會傳遞給 handler 函式。
event 代表事件
handler 代表事件要處理的方式(函式)
滑鼠和鍵盤事件
程式碼 | 說明 |
---|---|
<Button-1> 或 <ButtonPress-1>或<1> | 滑鼠左鍵按下。1=左鍵,2=中鍵,3=右鍵 |
<ButtonRelease-1> | 滑鼠左鍵釋放。 1=左鍵,2=中鍵,3=右鍵 |
<B1-Motion> | 滑鼠左鍵移動 |
<Double-Button-1> | 雙擊左鍵 |
<Enter> | 滑鼠指標進入某一元件區域 |
<Leane> | 滑鼠指標離開某一元件區域 |
<MouseWheel> | 滾動滑輪 |
<KeyPress> | 響應按下的任意鍵 |
<KeyPress-a> | 按下 a 鍵,a可自定義(a-zA-Z) |
<KeyRelease-a> | 釋放 a 鍵,a可自定義其它小寫字母 |
<Alt-KeyPress-a> | 同時按下 alt和a ;alt可用Ctrl和shift代替 |
<Double-KeyPress-a> | 快速雙擊a |
<Control-V> | Ctrl和V鍵同時按下,V可以自定義 |
event 物件常用屬性
名稱 | 說明 |
---|---|
char | 按鍵字元,僅對鍵盤事件有效 |
Keycode | 按鍵編碼,僅對鍵盤事件有效 |
Keysym | 按鍵名稱,僅對鍵盤事件有效。比如按下 a 鍵:char:a、 Keycode:65、Keysym:a |
num | 滑鼠按鍵,僅對滑鼠事件有效 |
type | 所觸發的事件型別 |
widget | 引起事件的元件 |
width,height | 元件改變後的大小,僅Configure有效 |
x,y | 滑鼠當前位置,相對於父容器 |
x_root,y_root | 滑鼠當前位置,相對於整個螢幕 |
示例:
import tkinter as tk
# 建立主視窗
root = tk.Tk()
root.title("TK title")
root.geometry("500x500+10+20")
''' 滑鼠和鍵盤事件 '''
C1 = tk.Canvas(root, width=200, height=200, bg='green')
C1.pack()
def mouseT(event):
print("滑鼠左鍵單擊位置(父容器):{},{}".format(event.x,event.y))
print("滑鼠左鍵單擊位置(螢幕):{},{}".format(event.x_root,event.y_root))
print("事件繫結的元件:{}".format(event.widget))
def dragT(event):
print("滑鼠移動點位置:", event.x, event.y, event.x+1, event.y+1)
C1.create_oval(event.x, event.y, event.x+10, event.y+10)
def keyboardT(event):
'''響應按下的任意鍵'''
print("鍵的keyconde:{}, 鍵的char:{}, 鍵的keysym:{}".format(event.keycode, event.char, event.keysym))
def press_a_T(event):
print("按下a鍵")
def release_a_T(event):
print("釋放a鍵")
# 對 C1 畫布範圍內有效
C1.bind("<Button-1>", mouseT)
C1.bind("<B1-Motion>", dragT)
# 對整個GUI介面有效
root.bind("<KeyPress>", keyboardT)
# 只針對小寫字母 a 有效
root.bind("<KeyPress-a>", press_a_T)
root.bind("<KeyRelease-a>", release_a_T)
root.mainloop() # 執行GUI
多種事件繫結方式
-
元件物件繫結
- 通過
command
屬性繫結(適合不需要獲取event物件)
Button(root, text='登入', command=login)
- 通過
bind()
方法繫結(合適需要獲取event物件)
c1 = tkinter.Canvas() c1.bind("<Button-1>", drawLine)
- 通過
-
元件類的繫結
呼叫物件的
bind_class
函式,將該元件型別的所有元件繫結事件:w.bind_class('Widget', 'event', eventhanler)
w 代表控制元件
Widget=控制元件,event=事件,eventhanler=呼叫函式
# 比如給GUI上的所有按鈕繫結事件 btn01.bind_class("Button", "<Button-1>",func)
示例:
import tkinter as tk root = tk.Tk() root.title("TK title") def mouseT(event): print("bind()方式繫結,可以獲取event物件:{}".format(event.widget)) def mouseT1(a,b): print("command方式繫結,不能獲取event物件:a={},b={}".format(a,b)) def mouset2(event): print("右鍵單擊事件,給所有的按鈕繫結事件:{}".format(event.widget)) btn1 = tk.Button(root, text="測試bind()事件繫結") btn1.pack() btn1.bind("<Button-1>", mouseT) # bind方式繫結 btn2 = tk.Button(root, text="測試command繫結", command=lambda :mouseT1('AA', "BB")) btn2.pack() # 繫結給所有的按鈕右鍵事件 btn2.bind_class("Button", "<Button-3>", mouset2) root.mainloop() # 執行GUI
OptionMenu 下拉選擇項
下拉選項,用來做多選一,選中的項在頂部顯示。
示例:
import tkinter as tk
root = tk.Tk()
root.title("TK title")
strvar = tk.StringVar()
strvar.set('程式設計') # 設定預設值
om = tk.OptionMenu(root, strvar, 'java', 'python', 'php')
om['width'] = 10
om.pack()
root.mainloop() # 執行GUI
Scale 移動滑塊
用於在指定的數值區間,通過滑塊的移動選擇值。
相關屬性:
activebackground, background, bigincrement, bd,bg, borderwidth, command, cursor, digits, fg, font, foreground, from,highlightbackground, highlightcolor, highlightthickness, label,
length, orient, relief, repeatdelay, repeatinterval, resolution,showvalue, sliderlength, liderrelief, state, takefocus, tickinterval, to, troughcolor, variable, width
示例:(預設為垂直方向)
import tkinter as tk
root = tk.Tk()
root.title("TK title")
def test(value):
print("滑塊的值:", value)
# 重新設定按鈕字型的大小,滑塊控制
lab.config(font=('宋體', value))
sca = tk.Scale(root, from_=5, to=50, length=200, tickinterval=5, command=test, orient='horizontal') # 滑塊方式,horizontal=水平
sca.pack()
lab = tk.Label(root, text='測試滑塊', width=10, height=1, fg='white', bg='black', font=('宋體', 5))
lab.pack()
root.mainloop() # 執行GUI
顏色選擇框
可以幫助我們設定背景色、前景色、畫筆色、字型顏色等等。
匯入方式:
from tkinter.colorchooser import askcolor
示例:
import tkinter as tk
from tkinter.colorchooser import askcolor
root = tk.Tk()
root.title("TK title")
def test():
# 建立顏色選擇器,color=預設顏色
ask = askcolor(color='red', title='顏色標題')
print("背景色:", ask) # 返回是 RGB 值
root.config(bg=ask[1]) # 修改背景顏色
tk.Button(root, text='選擇', command=test).pack()
root.mainloop() # 執行GUI
檔案對話方塊
可以幫助我們實現視覺化的操作目錄、檔案。最後將檔案、目錄的資訊傳入到程式中。
匯入方式:
from tkinter.filedialog import askopenfilename
常用函式:
函式名 | 對話方塊 | 說明 |
---|---|---|
askopenfilename(**options) | 檔案對話方塊 | 返回開啟的檔名 |
askopenfilenames(**options) | 檔案對話方塊 | 返回開啟的多個檔名列表 |
askopenfile(**options) | 檔案對話方塊 | 返回開啟檔案物件 |
askopenfiles(**options) | 檔案對話方塊 | 返回開啟的檔案物件的列表 |
askdirectory(**options) | 目錄對話方塊 | 返回目錄名 |
asksaveasfile(**options) | 儲存對話方塊 | 返回儲存的檔案物件 |
asksaveasfilename(**options) | 儲存對話方塊 | 返回儲存的檔名 |
options 常用的值:
引數 | 說明 |
---|---|
defaultextension | 預設字尾:.xxx 使用者沒有輸入則自動新增 |
filetypes=[(label1,pattern1),(label2,pattern2)] | 檔案顯示過濾器 |
initaldir | 初始目錄 |
initalfile | 初始目錄 |
parent | 父視窗,預設根視窗 |
title | 視窗標題 |
選擇檔案示例:
import tkinter as tk
from tkinter.filedialog import askopenfilename
root = tk.Tk()
root.title("TK title")
# initialdir=預設開啟目錄路徑,filetypes=檔案過濾
def test():
ask = askopenfilename(title='上傳檔案', initialdir='d:\\', filetypes=[('PY檔案','.py')])
show["text"] = ask
vv.set(ask) # 將選擇的檔案絕對路徑,輸入到文字框中
show = tk.Button(root, text='選擇檔案', command=test)
show.pack()
vv = tk.StringVar()
e = tk.Entry(root, textvariable=vv, width=50)
e.pack()
root.mainloop() # 執行GUI
直接讀取檔案的內容示例:
import tkinter as tk
from tkinter.filedialog import askopenfile
root = tk.Tk()
root.title("TK title")
def test():
with askopenfile(title='上傳檔案', initialdir="d:\\", filetypes=[('檔案', '.txt')]) as f:
show.delete(1.0, 'end') # 刪除文字框中之前的內容
show.insert('insert', f.read()) # 將讀取到的檔案內容寫入到文字框中
tk.Button(root, text='選擇檔案', command=test).pack()
show = tk.Text(root, width=60, height=20)
show.pack()
root.mainloop() # 執行GUI
對話彈框
simpledialog(簡單對話方塊)包含如下常用函式:
函式 | 說明 |
---|---|
askfloat(title,prompt,**kw) | 輸入並返回浮點數 |
askinteger(title,prompt,**kw) | 輸入並返回整數 |
askstring(title,prompt,**kw) | 輸入並返回字串 |
title 代表視窗標題;prompt 是提示描述內容;
kw 代表不定長引數,可以為:initialvalue(初始值), minvalue(最小值), maxvalue(最大值)
示例:
import tkinter as tk
from tkinter.simpledialog import askfloat, askinteger,askstring
root = tk.Tk()
root.title("TK title")
def integer_t(): # 其他兩個用法一樣
integer = askinteger(title='整數', prompt='請輸入整數:', initialvalue=10, minvalue=0, maxvalue=100)
show.insert('end', integer)
But = tk.Button(root, text='輸入整數', command=integer_t)
But.pack()
show = tk.Text(root, width=60, height=20)
show.pack()
root.mainloop() # 執行GUI
選單
主選單通常位於 GUI 程式的上方位置。
匯入方式:
from tkinter.filedialog import *
建立主選單步驟:
- 建立主選單欄物件:
menubar = tk.Menu(master=root)
- 建立選單選項,並新增到主選單欄物件中:
menuFile = tk.Menu(menubar)
menubar.add_cascade(label="檔案(F)", menu=menuFile)
menuEdit = tk.Menu(menubar)
menubar.add_cascade(label="編輯(E)", menu=menuEdit)
- 新增子選單項到第2步驟的選單中:
menuFile.add_command(label="新建", accelerator="ctrl+n", command=self.newfile)
menuFile.add_command(label="開啟", accelerator="ctrl+o", command=self.openfile)
menuEdit.add_command(label="查詢", accelerator="ctrl+f", command=self.test)
menuEdit.add_command(label="刪除", accelerator="ctrl+d", command=self.test)
- 將選單新增到root視窗:
root["menu"] = menubar
建立選單示例:
# ''' 建立主選單 '''
menubar = tk.Menu(root)
# ''' 建立子選單 '''
menuFile = tk.Menu(menubar)
menuEdit = tk.Menu(menubar)
menuHelp = tk.Menu(menubar)
# '''將子選單加入到主選單欄'''
# label=名稱;menu=對應的選單
menubar.add_cascade(label="檔案(F)", menu=menuFile)
menubar.add_cascade(label="編輯(E)", menu=menuEdit)
menubar.add_cascade(label="幫助(H)", menu=menuHelp)
# '''新增檔案菜中的子選單'''
# label=名稱;accelerator=快捷鍵方式描述;command=選項執行事件
menuFile.add_command(label="新建", accelerator="ctrl+n", command=self.newfile)
menuFile.add_command(label="開啟", accelerator="ctrl+o", command=self.openfile)
menuFile.add_command(label="儲存", accelerator="ctrl+s", command=self.savefile)
menuFile.add_separator() # 新增分割線
menuFile.add_command(label="退出", accelerator="ctrl+q", command=self.exit)
# '''新增編輯菜中的子選單'''
menuEdit.add_command(label="查詢", accelerator="ctrl+f", command=self.test)
menuEdit.add_command(label="刪除", accelerator="ctrl+d", command=self.test)
# '''新增幫助菜中的子選單'''
menuHelp.add_command(label="幫助", accelerator="ctrl+h", command=self.test)
# ''' 將主選單新增到 root 主視窗 '''
root["menu"] = menubar
建立滑鼠右鍵選單步驟:
- 建立選單物件:
contextMenu = tk.Menu(root)
- 建立選單選項:
contextMenu.add_command(label="背景顏色", command=openAskcolor)
def openAskcolor():
color = askcolor(color='red', title="選擇背景顏色", )
textpad.config(bg=color[1])
- 繫結滑鼠右鍵事件:
def createContextMenu(event):
# 右鍵選單,在滑鼠右鍵時顯示選單
contextMenu.post(event.x_root, event.y_root)
root.bind("<Button-3>", createContextMenu)
示例:
# 文字編輯區
self.textpad = Text(root, width=60, height=30)
self.textpad.pack()
# 建立滑鼠右鍵上下選單
self.contextMenu = tk.Menu(root)
self.contextMenu.add_command(label="背景顏色", command=self.openAskcolor)
# 右鍵繫結事件
root.bind("<Button-3>", self.createContextMenu)
def openAskcolor(self):
color = askcolor(color='red', title="選擇背景顏色", )
self.textpad.config(bg=color[1]) # 修改背景顏色
簡單記事本案例:
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter.ttk import Scrollbar, Checkbutton, Label, Button
import os
class NotePad(tk.Tk):
def __init__(self):
super().__init__()
self.set_window()
self.create_menu_bar()
self.create_body()
def set_window(self):
'''設定視窗引數'''
self.title("記事本")
max_width, max_height = self.maxsize() # 螢幕的大小
align_center = "800x600+%d+%d" % ((max_width-800)/2, (max_height-600)/2)
self.geometry(align_center)
self.iconbitmap("www.gif") # 圖示
def create_menu_bar(self):
''' 建立選單物件 '''
menu_bar = tk.Menu(self)
# 新增選單專案 tearoff=去掉預設分隔符
File_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="檔案", menu=File_menu) # 選單名稱
File_menu.add_command(label="開啟", accelerator="ctrl+o", command=self.open_file) # 下拉選單名稱
File_menu.add_separator()
File_menu.add_command(label="退出", accelerator="Ait+F4", command=self.quit) # 二級選單
Editor_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="編輯", menu=Editor_menu) # 選單名稱
Editor_menu.add_command(label="查詢", accelerator="Ctrl+F", command=self.find_text_dialog)
View_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="檢視", menu=View_menu) # 選單名稱
# 顯示行號
self.is_show_line = tk.IntVar()
self.is_show_line.set(1) # 預設從1開始
View_menu.add_checkbutton(label="顯示行號", onvalue=0, offvalue=1,
variable=self.is_show_line, command=self.update_line_num)
# 高亮當前行
self.is_height_line = tk.IntVar()
View_menu.add_checkbutton(label="高亮當前行", variable=self.is_height_line, command=self.toggle_row)
# 主題,下拉選單巢狀選單
themes_menu = tk.Menu(menu_bar, tearoff=0)
View_menu.add_cascade(label="主題", menu=themes_menu) # 選單名稱
themes_menu.add_command(label="主題1", accelerator="a+b", command="")
About_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="關於", menu=About_menu) # 選單名稱
About_menu.add_command(label="", command="")
# 將設定的選單專案加的選單欄中
self.config(menu=menu_bar)
def create_body(self):
''' 左邊=行號,中間編輯區,右邊=滾動條 '''
# 行號區域
self.line_num_bar = tk.Text(self, width=2, padx=1, takefocus=0, border=0,
background="#AAADAA", state="disable")
self.line_num_bar.pack(side="left", fill="y")
# 文字編輯區
self.context_text = tk.Text(self, wrap="word", undo=True)
self.context_text.pack(fill="both", expand='yes')
# 熱鍵繫結-注意按鍵引數會傳入到指定事件中
self.context_text.bind("<Control-o>", self.open_file)
self.context_text.bind("<Any-KeyPress>", self.update_line_num)
self.context_text.bind('<Button-1>', self.toggle_row)
# 設定文字輸入區域
self.context_text.tag_config("active_line", background="#F7E3AD")
# 垂直滾動條
scroll_bar = Scrollbar(self.context_text) # 將滾動條與文字框關聯
scroll_bar['command'] = self.context_text.yview # 將滾動條與文字框的Y軸關聯
self.context_text["yscrollcommand"] = scroll_bar.set # 將文字框的Y軸滾動交給滾動條處理
scroll_bar.pack(side="right", fill="y")
def open_file(self, event=None):
''' 開啟檔案 '''
input_fiel = filedialog.askopenfilename(filetype=[("文字型別", ".txt"), ("所有型別", "*.*")])
if input_fiel:
# 不同狀態,修改標題顯示
self.title("{}**".format(os.path.basename(input_fiel)))
self.context_text.delete(1.0, "end")
with open(input_fiel, "r") as f:
self.context_text.insert(1.0, f.read())
else:
messagebox.showerror("錯誤", "開啟檔案失敗!")
def update_line_num(self, event=None):
''' 行號處理 '''
# self.is_show_line.get 0:代表選中, 1:代表未選中
if self.is_show_line.get() == 0:
# 獲取所有的行
row, col = self.context_text.index("end").split(".")
# 列舉每行的行號
line_num_content = "\n".join([str(i) for i in range(1, int(row))])
self.line_num_bar.config(state="normal")
self.line_num_bar.delete(1.0, "end")
self.line_num_bar.insert(1.0, line_num_content)
self.line_num_bar.config(state="disable")
else:
self.line_num_bar.config(state="normal")
self.line_num_bar.delete(1.0, "end")
self.line_num_bar.config(state="disable")
def toggle_row(self, event=None):
''' 高亮行 '''
if self.is_height_line.get():
self.context_text.tag_remove("active_line", 1.0, "end")
# 設定高亮
self.context_text.tag_add("active_line", "insert linestart", "insert lineend+1c")
# 通過遞迴方式進行處理 或 滑鼠左鍵事件
# self.context_text.after(200, self.toggle_row)
else:
self.context_text.tag_remove("active_line", 1.0, "end")
def find_text_dialog(self):
''' 查詢對話方塊 '''
# 查詢對話方塊大小設定
search_dialog = tk.Toplevel(self)
search_dialog.title("查詢文字")
max_width, max_height = self.maxsize()
align_center = "300x80+{}+{}".format(int((max_width-300)/2), int((max_height-80)/2))
search_dialog.geometry(align_center)
search_dialog.resizable(False, False)
Label(search_dialog, text="查詢全部").grid(row=0, column=0, sticky="e")
search_text = tk.Entry(search_dialog, width=25)
search_text.grid(row=0, column=1, padx=2, pady=2, sticky="we")
search_text.focus_set()
# 忽略大小寫
ignore_case_value = tk.IntVar()
Checkbutton(search_dialog, text="忽略大小寫", variable=ignore_case_value).grid(
row=1, column=1, padx=2, pady=2, sticky="e")
Button(search_dialog, text="查詢", command=lambda: self.search_result(search_text.get(),
ignore_case_value.get(), search_dialog, search_text)).grid(row=0, column=2,
sticky='w'+"e", padx=10, pady=1)
# 關閉
def colse_search_dialog():
self.context_text.tag_remove('match', 1.0, 'end')
search_dialog.destroy()
search_dialog.protocol('WM_DELETE_WINDOW', colse_search_dialog)
return "break"
def search_result(self, text, ignore_case, search_dialog, search_box):
'''
:param text: 要查詢的文字內容
:param ignore_case: 是否忽略大小寫
:param search_dialog: 查詢的目標窗體
:param search_box: 查詢結果焦點
'''
# 清楚匹配內容
self.context_text.tag_remove('match', 1.0, 'end')
matches_found = 0
if text:
start_pos = 1.0
while True:
start_pos = self.context_text.search(text, start_pos, nocase=ignore_case, stopindex='end')
if not start_pos:
break
end_pos = "{}+{}c".format(start_pos, len(text))
self.context_text.tag_add('match', start_pos, end_pos)
matches_found += 1
start_pos = end_pos
self.context_text.tag_config('match', foreground="red", background="yellow")
search_box.focus_set()
search_dialog.title("發現了 %d 個匹配項" % matches_found)
if __name__ == '__main__':
app = NotePad()
app.mainloop()