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