Python 升級之路 ( Lv19 ) GUI 編程
今天我們將深入學習GUI圖形界面編程tkinter, 了解基礎組件的使用方式。
tkinter基礎組件
在登上天維巨獸身上的時候, 了不起大吃一驚. 作為堪比一個島嶼的存在, 這個生物的身上好像蘊藏著無數的奧秘. 可是剛一下來迎接他們的不是鮮花和掌聲, 而是一把匕首. GBK教信徒蜂擁而至, 由于大家事先都知道這些信徒是被控制的, 因此都特意留手. 盡量都將其擊暈, 然后由奧菲利亞通過使用凈化魔法來解決. 花費了近一天的時間, 才將近百名被控制的信徒解救成功. 然后在恢復意識的信徒的帶領下, 了不起進入到了神殿外圍的核心地區. 這里有GBL的大祭司和大神官, 也是奧菲利亞昔日的朋友...
Label 標簽
Label(標簽)主要用于顯示文本信息,也可以顯示圖像。
常用屬性:
- width,height: 用于指定區域大小 如果顯示是文本,則以單個英文字符大小為單位(一個漢字寬度占 2 個字符位置,高度和英文字符一樣);如果顯示是圖像,則以像素為單位。默認值是 根據具體顯示的內容動態調整
- font: 指定字體和字體大小. 如:font = (font_name,size)
- image: 顯示在 Label 上的圖像,目前 tkinter 只支持 gif 格式
- fg 和 bg: fg(foreground):前景色、bg(background):背景色
- justify: 針對多行文字的對齊,可設置 justify 屬性,可選值"left", "center" or "right"
實操代碼:
"""測試 Label 組件的基本用法,使用面向對象的方式"""
from tkinter import *
class Application(Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
"""創建組件"""
self.label01 = Label(self, text="點擊label", width=10, height=2, bg="black", fg="white")
self.label01["text"] = "第一個Label"
self.label01.config(fg="red", bg="green")
self.label01.pack()
self.label02 = Label(self, text="第二個Label", width=10, height=2, bg="blue", fg="white", font=("黑體", 30))
self.label02.pack()
# 顯示圖像
global photo # 把 photo 聲明成全局變量. 如果是局部變量,本方法執行完畢后,圖像對象銷毀,窗口顯示不出圖像
photo = PhotoImage(file="111.gif")
self.label03 = Label(self, image=photo)
self.label03.pack() # 在父小部件中打包一個小部件
self.label04 = Label(self, text="第一行\n 第二行\n 第三行", borderwidth=5, relief="groove", justify="right")
self.label04.pack()
if __name__ == "__main__":
root = Tk()
root.geometry("600x600+810+330")
root.title("測試Label")
app = Application(master=root)
root.mainloop()
注意:
- Label(標簽)主要用于顯示文本信息,也可以顯示圖像
- pack 按照組件的創建順序將子組件添加到父組件中,按照垂直或者水平的方向自然排布 如果不指定任何選項,默認在父組件中自頂向下垂直添加組件. pack 是代碼量最少最簡單的一種,可以用于快速生成界面.
Options 選項詳解
通過學習 Label 組件,我們發現可以通過 Options 設置組件的屬性,從而控制組件的各種狀態. 比如:寬度、高度、顏色、位置等等。
可以通過以下三種方式設置 Options 選項,這在各種 GUI 組件中用法都一致:
- 創建對象時,使用可變參數fred = Button(self, fg="red", bg="blue")
- 創建對象后,使用字典索引方式
fred["fg"] = "red"
fred["bg"] = "blue"
- 創建對象后,使用 config()方法 fred.config(fg="red", bg="blue")
如何查看組件的 Options 選項?
- 可以通過打印 config()方法的返回值,查看 Options 選項 print(fred.config())
- 通過在 IDE 中,ctrl+鼠標左鍵 即可進入組件對象的構造方法,進入到方法內觀察:
上面代碼中有:“standard options 標準選項”和“widget-specific options 組件特定選項”. 我們將常見的選項匯總如下:
Button 按鈕
Button(按鈕)用來執行用戶的單擊操作. Button 可以包含文本,也可以包含圖像 按鈕被單擊后會自動調用對應事件綁定的方法. 相關屬性參數介紹見上面Options 選項詳解部分圖片。
實操代碼:
"""
Button(按鈕)用來執行用戶的單擊操作
Button 可以包含文本,也可以包含圖像。按鈕 被單擊后會自動調用對應事件綁定的方法
"""
from tkinter import *
from tkinter import messagebox
class Application(Frame):
def __init__(self, master):
super().__init__(master) # super()代表的是父類的定義, 而不是父類的對象
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
"""創建組件"""
self.btn01 = Button(root, text="登錄", width=4, height=1, anchor=NE, command=self.login)
self.btn01.pack()
global photo
photo = PhotoImage(file="111.gif")
self.btn02 = Button(root, image=photo, command=self.login)
self.btn02.pack()
self.btn02.config(state="disabled") # 設置按鈕為禁用
def login(self):
messagebox.showinfo("智慧終端學習系統", "登錄成功!歡迎開始學習!")
if __name__ == '__main__':
root = Tk()
root.title("測試Button")
root.geometry("400x400+200+300")
app = Application(master=root)
root.mainloop()
運行結果:
利用 lambda 表達式實現傳參
lambda 表達式定義的是一個匿名函數,只適合簡單輸入參數,簡單計算返回結果,不適合功能復雜情況lambda 定義的匿名函數也有輸入、也有輸出,只是沒有名字。
語法格式如下:
lambda 參數值列表:表達式
lambda 表達式的參數值列表可以為如下內容
實操代碼:
from tkinter import Tk, Button
root = Tk()
root.geometry("270x50")
def mouseTest1():
print("command 方式,簡單情況:不涉及獲取 event 對象,可以使用")
def mouseTest2(a,b):
print("a={0},b={1}".format(a,b))
Button(root, text="測試 command1", command=mouseTest1).pack(side="left")
"""
lambda 定義的匿名函數也有輸入、也有輸出,只是沒有名字。語法格式如下: lambda 參數值列表:表達式 參數值列表即為輸入。 表達式計算的結構即為輸出。
"""
Button(root, text="測試 command2", command=lambda: mouseTest2("實參1傳入", "實參2傳入")).pack(side="left")
root.mainloop()
結果展示:
Entry 單行文本框
Entry 用來接收一行字符串的控件. 如果用戶輸入的文字長度長于 Entry 控件的寬度時, 文字會自動向后滾動 如果想輸入多行文本, 需要使用 Text 控件.
Entry構造函數如下圖, 相關屬性參數介紹見上面Options 選項詳解部分圖片:
實操代碼:
"""
Entry 用來接收一行字符串的控件。如果用戶輸入的文字長度長于 Entry 控件的寬度時,
文字會自動向后滾動。如果想輸入多行文本, 需要使用 Text 控件。
"""
# 【示例】Entry 單行文本框實現簡單登錄界面
from tkinter import *
from tkinter import messagebox
class Appliaction(Frame):
def __init__(self, master):
super().__init__(master)
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
"""創建登錄界面的組件"""
self.label01 = Label(self, text="用戶名")
self.label01.pack()
# StringVar 變量綁定到指定的組件
# StringVar 變量的值發生變化,組件內容也變化;
# 組件內容發生變化,StringVar 變量的值也發生變化
v1 = StringVar()
self.entry01 = Entry(self, textvariable=v1)
self.entry01.pack()
v1.set("admin")
print(v1.get())
print(self.entry01.get())
# 創建密碼框
self.btn02 = Label(self, text="密碼")
self.pack()
v2 = StringVar()
self.entry02 = Entry(self, textvariable=v2, show="*")
self.entry02.pack()
Button(self, text="登錄", command=self.login).pack()
def login(self):
title = "智慧終端學習系統"
username = self.entry01.get()
pwd = self.entry02.get()
print("去數據庫對比密碼")
print("用戶名" + username)
print("密碼" + pwd)
if username == "TimePause" and pwd == "123456":
messagebox.showinfo(title, "登陸成功! 歡迎開始學習!")
else:
messagebox.showinfo(title, "登錄失敗, 用戶名密碼錯誤")
if __name__ == "__main__":
root = Tk()
root.title("智慧終端學習系統")
root.geometry("400x130+200+300")
app = Appliaction(master=root)
root.mainloop()
結果展示:
Text 多行文本框
Text(多行文本框)的主要用于顯示多行文本,還可以顯示網頁鏈接, 圖片, HTML 頁面, 甚至 CSS 樣式表,添加組件等因此,也常被當做簡單的文本處理器、文本編輯器或者網 頁瀏覽器來使用。比如 IDLE 就是 Text 組件構成的。
Text 構造函數如下圖, 相關屬性參數介紹見上面Options 選項詳解部分圖片:
實操代碼:
"""
Text(多行文本框)的主要用于顯示多行文本,還可以顯示網頁鏈接, 圖片, HTML 頁面, 甚至 CSS 樣式表,添加組件等。
因此,也常被當做簡單的文本處理器、文本編輯器或者網 頁瀏覽器來使用。比如 IDLE 就是 Text 組件構成的。
"""
from tkinter import *
import webbrowser
class Application(Frame):
def __init__(self, master=None): # 這里相當于java中定義了一個帶參構造. master指代的是一個形參, 為后面創建類的對象時使用
super().__init__(master) # super()代表的是父類的定義,而不是父類對象
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
self.w1 = Text(root, width=40, height=12, bg="gray") # 寬度 20 個字母(10 個漢字),高度一個行高
self.w1.pack()
self.w1.insert(1.0, "0123456789\nabcdefg")
self.w1.insert(2.3, "鋤禾日當午,汗滴禾下土。誰知盤中餐,粒粒皆辛苦\n")
Button(self, text="重復插入文本 ", command=self.insertText).pack(side="left")
Button(self, text="返回文本", command=self.returnText).pack(side="left")
Button(self, text="添加圖片", command=self.addImage).pack(side="left")
Button(self, text="添加組件", command=self.addWidget).pack(side="left")
Button(self, text="通過 tag 精確控制文本 ", command=self.testTag).pack(side="left")
def insertText(self):
self.w1.insert(INSERT, ' 測試插入 ') # INSERT 索引表示在光標處插入
self.w1.insert(END, '測試尾插') # END 索引號表示在最后插入
self.w1.insert(1.8, "測試指定位置插入") # Indexes(索引)是用來指向 Text 組件中文本的位置,Text 的組件索引也是對應實際字符之間的位置
def returnText(self):
print(self.w1.get(1.2, 1.6))
print("所有文本內容:\n" + self.w1.get(1.0, END)) # 核心:行號以 1 開始 列號以 0 開始
def addImage(self):
global photo
self.photo = PhotoImage(file="111.gif")
self.w1.image_create(END, image=self.photo)
def addWidget(self):
b1 = Button(self.w1, text='創建一個新組件') # 在 text 創建組件的命令
self.w1.window_create(INSERT, window=b1)
def webshow(self):
webbrowser.open("http://www.baidu.com")
def testTag(self):
self.w1.delete(1.0, END)
self.w1.insert(INSERT, "good good study,day day up!\n 測試 baidu\n Tag標簽\n 精準控制文本")
self.w1.tag_add("good", 1.0, 1.9)
self.w1.tag_config("good", background="yellow", foreground="red")
self.w1.tag_add("baidu", 4.1, 4.3)
self.w1.tag_config("baidu", underline=True)
self.w1.tag_bind("baidu", "<Button-1>", self.webshow)
if __name__ == '__main__':
root = Tk()
root.title("測試多行文本text")
root.geometry("450x300+200+300")
app = Application(master=root)
root.mainloop()
結果展示:
Radiobutton 單選按鈕
Radiobutton 控件用于選擇同一組單選按鈕中的一個, 可以顯示文本,也可以 顯示圖像。
實操代碼:
"""測試 Radiobutton 組件的基本用法,使用面向對象的方式"""
from tkinter import Frame, Radiobutton, Button, messagebox, Tk, StringVar
class Application(Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.createWidget()
def createWidget(self): # 定義組件
self.v1 = StringVar()
self.v1.set("F")
self.r1 = Radiobutton(self, text="男性", value="M", variable=self.v1) # 定義單選框
self.r2 = Radiobutton(self, text="女性", value="F", variable=self.v1)
self.r1.pack(side="left")
self.r2.pack(side="left")
Button(self, text="確定", command=self.confirm).pack(side="left")
def confirm(self):
messagebox.showinfo("測試", "選擇性別" + self.v1.get()) # 定義彈窗信息
if __name__ == '__main__':
root = Tk()
root.geometry("400x50+200+300")
app = Application(root)
root.mainloop()
結果展示:
Checkbutton 復選按鈕
Checkbutton 控件用于選擇多個按鈕的情況. 可以顯示文本,也可以顯示圖像。
實操代碼:
"""測試 Checkbutton 組件的基本用法,使用面向對象的方式"""
from tkinter import Frame, IntVar, Checkbutton, Button, messagebox, Tk
class Application(Frame):
# 創建構造方法
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.createWidget()
# 創建組件, 創建復選框并設置屬性.
def createWidget(self):
self.codeHobby = IntVar()
self.videoHobby = IntVar()
self.c1 = Checkbutton(self, text="敲代碼", variable=self.codeHobby, onvalue=1, offvalue=0)
self.c2 = Checkbutton(self, text="看視頻", variable=self.videoHobby, onvalue=1, offvalue=0)
self.c1.pack(side="left")
self.c2.pack(side="left")
# 創建確定按鈕并創建對象的提示框
self.b = Button(self, text="確定", command=self.showInfo).pack(side="left") # 這里command傳入的是方法的對象
def showInfo(self):
if self.codeHobby.get() == 1 and self.videoHobby.get() == 1:
messagebox.showinfo("提示框", "既愛看視頻又愛學習, 來我這里學編程吧")
elif self.codeHobby.get() == 1: # IntVar需要調用get方法才能獲得
messagebox.showinfo("提示框", "你這個人愛學習編程啊, 學python吧")
elif self.videoHobby.get() == 1:
messagebox.showinfo("提示框", "你這個人比較愛看視頻啊, 少看點")
else:
messagebox.showinfo("提示框", "啥都不愛啊, 隨便選一個作為你的愛好吧")
# 啟動方法以及相關組件信息
if __name__ == "__main__":
root = Tk()
root.geometry("400x50+200+300")
app = Application(root)
root.mainloop()
結果展示:
canvas 畫布
canvas(畫布)是一個矩形區域,可以放置圖形、圖像、組件等。
實操代碼:
import random
from tkinter import Frame, Canvas, PhotoImage, Button, Tk
class Application(Frame):
# 1. 初始化
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.createWidget()
def createWidget(self):
# 2. 組件相關
self.canvas = Canvas(self, width=300, height=200, bg="green")
self.canvas.pack()
# 畫一條線
line = self.canvas.create_line(10, 10, 30, 20, 40, 50)
# 畫矩形
reat = self.canvas.create_rectangle(50, 50, 100, 100)
# 畫橢圓, 前后一對坐標為橢圓的邊界矩形左上角和底部右下角
oval = self.canvas.create_oval(50, 50, 100, 100)
global photo
photo = PhotoImage(file="111.gif")
self.canvas.create_image(250, 250, image=photo)
Button(self, text="來畫10個矩形", command=self.draw10rect).pack(side="left")
def draw10rect(self):
for i in range(0, 10):
x1 = random.randrange(int(self.canvas["width"]) / 2)
y1 = random.randrange(int(self.canvas["height"]) / 2)
x2 = x1 + random.randrange(int(self.canvas["width"]) / 2)
y2 = y1 + random.randrange(int(self.canvas["height"]) / 2)
self.canvas.create_rectangle(x1, y1, x2, y2)
if __name__ == "__main__":
root = Tk()
root.geometry("400x300+200+300")
app = Application(root)
root.mainloop()
結果展示:
不同于之前的信徒, 大主教和大祭司實力更加強大, 而且被控制的程度更深. GSC事先進行了分工: 由導師GSC對付大主教, 而了不起對付大祭司. 而當面對真正的強者時, GSC才真正認真起來. 開啟名為殺意波動的領域, 只見很大一片區域內, 包括了不起和大祭司所在的區域, 處在領域內的敵人行動明顯變得遲緩, 并且眼神中的瘋狂仿佛被壓制了不少. 了不起趕緊抓住機會, 使用起最近學習到的突刺技能, 在奧菲利亞的增幅下, 命中領主. 大祭司受傷之后, 開始瘋狂的召喚GBK教徒, 向其沖去. 然而在導師領域和奧菲利亞的增幅下, 不一會便將這些教徒擊暈. 了不起毫不畏懼,步步為營. 近身戰結合遠程法術, 花費半天時間終于將其在絲血時擊暈. 最后在奧菲利亞的凈化魔法的幫助下, 大主教和大祭司都恢復了意識. 而他們脫口而出的第一句話, 便讓了不起驚掉下巴...??
之間他們蘇醒之后, 脫口而出的第一句話便是: 偉大的教主大人, 請原諒我等所犯下的罪行...什么? 原來了不起拯救的紅發少女是GBK的教主. 在他們三者溝通完畢后, 奧菲利亞也略顯歉意地向了不起解釋道, 由于之前得知阿拉德大陸上的人都比較奸詐的, 擔心我們圖謀不軌, 因此沒說明其真正身份. 在幫助大祭司和大神官接觸控制之后, 明白了我們的偉人, 于是說明情況并請求我們的原諒. 而了不起的心里也有震驚中慢慢恢復, 在原諒了她之后便回到GBK外圍住所從長記憶...而了不起由于這兩天參與的高強度戰斗與大批量敵人的遭遇, 竟然從lv17升到了lv20。