以下內容為本人的學習筆記,如需要轉載,請宣告原文鏈接 微信公眾號「ENG八戒」https://mp.weixin.qq.com/s/B1hH5Qzd2RkAiiUId1tLWw
本文大概 2874 個字,閱讀需花 10 分鐘
內容不多,但也花了一些精力
如要交流,歡迎關注我然后評論區留言
謝謝你的點贊收藏分享
進入正文之前先說一件小事,本公眾號已改名為【ENG八戒】,原名是【englyf】,改名的理由是什么?以后會告訴朋友們的!
另外文末有福利彩蛋,畢竟今天是元宵節!
這篇文章屬于系列文章《Python 內置界面開發框架 Tkinter入門篇》的第三篇,上接《Python 內置界面開發框架 Tkinter入門篇 乙》,歡迎關注我的微信公眾號「ENG八戒」查看這個系列相關文章,
界面布局
關于 Tkinter 框架的 GUI 布局,其實官方沒有提供對應的圖形化工具可用,但是網上有一些開源的小工具可以使用,這里不打算介紹這些小工具的使用,而是直接用框架提供的幾何圖形管理器來布局,比如上面提到過的 pack() 就是其中一種,這里提到的幾何圖形管理器也就是其它框架里常說的布局管理器,
Tkinter 框架提供的布局管理器有:pack、grid、place 三種,每一個控制元件只可以使用一種布局管理器,不同控制元件使用的布局管理器可以不一樣,
pack
形象點說, pack 就是把控制元件包裝在一個矩形區域,這個區域大小足夠放置控制元件,而且默認置中,pack 是最簡單的布局管理器,也稱之為包裝布局,
直接試一試用 pack 來布局三個靜態標簽 Label,默認設定(pack() 傳入引數為空)
import tkinter as tk
window = tk.Tk()
lbl_1 = tk.Label(
master=window,
text="label 1",
fg="black",
bg="red",
width=10,
height=5
)
lbl_1.pack()
lbl_2 = tk.Label(
master=window,
text="label 2",
fg="black",
bg="yellow",
width=10,
height=5
)
lbl_2.pack()
lbl_3 = tk.Label(
master=window,
text="label 3",
fg="black",
bg="blue",
width=10,
height=5
)
lbl_3.pack()
window.mainloop()
看看顯示效果
可以看到,默認 pack 會在父視窗 window 中垂直方向按順序包裝排列這三個靜態標簽 Label,
那么,如果我需要讓這幾個標簽水平排列呢?可以這樣子改
lbl_1.pack(side=tk.LEFT)
...
lbl_2.pack(side=tk.LEFT)
...
lbl_3.pack(side=tk.LEFT)
看看顯示效果
pack(side=tk.TOP) 和默認設定等價,
簡單匯總介紹一下其它的引數
引數 | 賦值 | 說明 |
---|---|---|
after | 控制元件 widget | 將此控制元件包裝在控制元件 widget 后邊 |
anchor | NSEW (or subset) | 根據方向定位此控制元件,NSEW 表示北南東西四個方向 |
before | 控制元件 widget | 將此控制元件包裝在控制元件 widget 前邊 |
expand | bool 型別值 | 跟著父控制元件一起伸縮 |
fill | NONE、X、Y、BOTH | 選擇當控制元件伸縮時按照哪個方向填充 |
ipadx | amount | 在x方向添加內部填充 |
ipady | amount | 在y方向添加內部填充 |
padx | amount | 在x方向添加填充 |
pady | amount | 在y方向添加填充 |
side | TOP、BOTTOM、LEFT、RIGHT | 把控制元件往哪邊添加 |
很多時候開發界面都需要讓里邊的控制元件跟隨視窗自動拉伸大小,來看一下上面的代碼應該怎么改
lbl_1.pack(fill=tk.BOTH, expand=tk.TRUE)
...
lbl_2.pack(fill=tk.BOTH, expand=tk.TRUE)
...
lbl_3.pack(fill=tk.BOTH, expand=tk.TRUE)
啟動的時候,還沒有拉伸視窗
然后拉伸看看
grid
如名字表述,grid 會把父視窗劃分成行列,然后根據呼叫時傳入引數 row,column 確定把控制元件放置在對應的行列中,grid 也稱之為格子布局,
還是以靜態標簽為例,創建 3x3 的矩陣標簽,為了凸顯各個標簽的邊界,這里還需要添加 Frame 控制元件,每個標簽放置于單獨的 Frame 中,
import tkinter as tk
window = tk.Tk()
for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(
master=frame,
text=f"Row {i}\nColumn {j}"
)
label.pack()
window.mainloop()
可以看到,上面這個例子布局時,只有 Frame 才需要應用 grid 管理器,因為每個標簽和 Frame 一一對應,所以標簽不需要重復應用格子布局,
看看顯示效果
簡單匯總介紹一下其它的引數
引數 | 賦值 | 說明 |
---|---|---|
column | 列序號 | 指定放置的列,從0開始 |
columnspan | 列數 | 放置的控制元件橫跨多少列 |
ipadx | amount | 在 x 方向添加內部填充 |
ipady | amount | 在 y 方向添加內部填充 |
padx | amount | 在 x 方向添加外部填充 |
pady | amount | 在 y 方向添加外部填充 |
row | 行序號 | 指定放置的行,從0開始 |
rowspan | number | 放置的控制元件橫跨多少行 |
sticky | NSEW | 如果單元格比較大,那么控制元件的指定邊界將貼著單元格,NSEW分別對應頂部、底部、右邊、左邊邊界 |
細心的朋友會發現,一旦拉伸上面的那個矩陣標簽視窗,視窗界面就會露出部分底面,矩陣標簽沒有跟隨一起拉伸,
這樣明顯和我們的預期不符合,這個問題怎么解決呢?
可以呼叫父視窗的 columnconfigure() 和 rowconfigure() 方法配置各列和行的伸縮比,這兩個方法都有三個輸入引數,看下面的表格
引數 | 說明 |
---|---|
index | 序號,指定特定的行或列,可以是單個行列序號值,也可以是代表多個行或列的串列 |
weight | 伸縮權重 |
minsize | 最小寬度值 |
現在來看看怎么改,才能讓矩陣標簽跟隨父視窗一起拉伸?
import tkinter as tk
window = tk.Tk()
for i in range(3):
window.rowconfigure(i, weight=1)
window.columnconfigure(i, weight=1)
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(
master=frame,
text=f"Row {i}\nColumn {j}"
)
label.pack()
window.mainloop()
看看拉伸之后的顯示效果
perfect!另外需要提一下,grid 具有 pack 能做的所有功能,但是使用的形式更簡單,因此應該作為更優先的布局管理器,
place
place 用于對控制元件精確定位的場合,使用的時候需要傳入引數 x 和 y 分別用于指定控制元件的放置位置坐標值 x 和 y,傳入的 x 和 y 是基于父控制元件的左上角為原點的坐標系,單位是像素點,
大多數界面應用里,控制元件都不需要精確的定位,但是某些,比如地圖應用里,就的確需要對元素的精確定位了,
下面舉個栗子,在視窗里不同位置放置各一個標簽
import tkinter as tk
window = tk.Tk()
label1 = tk.Label(
master=window,
text="place (0, 0)",
bg="yellow"
)
label1.place(x=0, y=0)
label2 = tk.Label(
master=window,
text="place (40, 40)",
bg="blue"
)
label2.place(x=40, y=40)
window.mainloop()
看看上面代碼的顯示效果
說回來,place 的引數xy單位是像素,那么在不同的系統下,字體型別和大小都是不同的,那么被放置的控制元件就有可能超出視窗邊界,因此 place 真的不常用,關于 place 進一步的資訊就不再展開了,
互動
上面介紹的內容都僅限于 Tkinter 界面的可視化設計,那么現在是時候介紹一下Tkinter 界面和用戶的互動了,
比如,Tkinter 界面對于事件的回應是怎么發生的?
一般,在 Tkinter 中通過預先系結事件和回應處理函式,每當事件發生時,主視窗的 mainloop 就會收到事件,然后根據系結資訊,查找到回應處理函式并呼叫,來達到互動的效果,系結的通用方法是呼叫各個控制元件的 bind(),
比如,下面我們來實作一個簡單的鍵盤回應互動,每次按鍵按下時就把對應的按鍵列印出來
import tkinter as tk
def handle_keypress(event):
print(event.char)
window = tk.Tk()
window.bind("<Key>", handle_keypress)
window.mainloop()
上面的代碼沒有添加額外的控制元件,除了有個空白的主視窗,其中,對主視窗 window 系結了按鍵事件 Key 和處理函式 handle_keypress,
呼叫 bind() 最少要求輸入兩個引數,一個是形式為 "<event_name>" 的事件,另一個是事件處理函式,
定義處理函式 handle_keypress 時,唯一做的事情是把傳入的事件字符列印到標準終端,
每當按下鍵盤的按鍵,命令列終端就會輸出對應的按鍵,
但是,對于按鈕 Button 來說,點擊事件的觸發處理可以不需要使用 bind(),僅需要在實體化控制元件 Button 時,傳入處理函式給 command 引數即可,初始化程序會自動系結 click 事件的回應,
上代碼看看
import tkinter as tk
def handle_keypress():
print("clicked")
window = tk.Tk()
button = tk.Button(
master=window,
text="click me!",
command=handle_keypress
)
button.pack()
window.mainloop()
運行程式
用滑鼠點擊一下界面上的按鈕,發現終端會輸出字串 clicked
由于篇幅受限,本系列教程還未完結,下一篇《Python 內置界面開發框架 Tkinter入門篇 丁》將在本公眾號稍后推送,如果你對此教程有興趣或者想和我一起交流更多精彩內容,歡迎關注我的微信公眾號 【ENG八戒】,等著你哦!
《元宵彩蛋》
鬧元宵了,《八戒陪你一起鬧元宵2023》
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/543058.html
標籤:Python
上一篇:Odoo 選單定義和修改學習總結
下一篇:【轉載】R語言 面向物件編程