您的位置:首页 > 编程语言 > Python开发

Python GUI Cookbook —— 创建 GUI 窗体并添加 Widgets

2017-12-03 10:07 756 查看
原文链接:Python GUI Cookbook —— 创建 GUI 窗体并添加 Widgets

创建第一个 Python GUI 程序

使用 Python 内置的 tkinter 模块,仅需 4 行代码就能创建一个 GUI。

下面是代码:

#!/usr/bin/env python3

import tkinter as tk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Start GUI
window.mainloop()




防止窗口大小被调整

使用 tkinter 创建的 GUI 默认是能够调整大小的,但有时候我们希望窗体保持特定的大小,因此需要学习如何防止用户调整 GUI 大小。

#!/usr/bin/env python3

import tkinter as tk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Disable resizing the GUI by passing in False/False
window.resizable(False, False)

# Enable resizing x-dimension, disable y-dimension
# window.resizable(True, False)

# Start GUI
window.mainloop()




在窗体中添加 label

label
是一种简单的 widget,它能够向窗体中添加值(value),能够解释其他 widgets 的目的,提供额外的信息。

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Add a Label
ttk.Label(window, text = 'A Label').grid(column=0, row=0)

# Start GUI
window.mainloop()




这里我们从 tkinter 包导入了一个独立模块 ttk。ttk 模块有一些高级 widgets 能够让我们的 GUI 看起来更好看。ttk 代表 themed tk。

在这个实例中我们使用了
ttk.Label
构造器设置文本属性(text property)

使用了网格布局管理器(grid layout manager)

可以发现窗体突然变小了好多,这是因为我们在窗体中添加了 widget,触发了优化,尽量使用小空间显示 widget(s)。

创建按钮并改变其文本属性

这里我们将添加一个
button
widget,并使用该按钮(button)改变其他 widget 的属性。我们将学习 Python GUI 的回调函数(callback function)和事件处理机制。

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Button click Event Function
def click_me():
action.configure(text='** I have been Clicked! **')
a_label.configure(foreground='red')
a_label.configure(text='A Red Label')

# Adding a Button
action = ttk.Button(window, text='Click Me!', command=click_me)
action.grid(column=1, row=0)

# Start GUI
window.mainloop()






GUIs 是事件驱动的。点击按钮产生一个事件。我们将事件产生时会发生的事与回调函数绑定。通过
ttk.Button
widget 的 command 属性调用它,注意调用时不需要圆括号,只需使用名字
click_me


文本框 Text Box widgets

在 tkinter 中,只有一行的
textbox
widget 被称为
Entry


#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Modified Button click Event Function
def click_me():
action.configure(text='Hello ' + name.get())

# Changing our Label
ttk.Label(window, text='Enter a name: ').grid(column=0, row=0)

# Adding a Text Box Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(window, width=12, textvariable=name)
name_entered.grid(column=0, row=1)

# Adding a Button
action = ttk.Button(window, text="Click Me!", command=click_me)
action.grid(column=1, row=1)

# Start GUI
window.mainloop()






在 tkinter 中,我们需要声明
name
变量为
tk.StringVar()
。因为 tkinter 不是 Python。我们只是能够在 Python 中使用它,但它们并不是同种语言。

给 widget 设置焦点,禁用 widgets

只需调用
focus()
方法就能给一个 widget 设置焦点。

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Modified Button click Event Function
def click_me():
action.configure(text='Hello ' + name.get())

# Changing our Label
ttk.Label(window, text='Enter a name:').grid(column=0, row=0)

# Adding a Text Box Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(window, width=12, textvariable=name)
name_entered.grid(column=0, row=1)

# Adding a Button
action = ttk.Button(window, text="Click Me!", command=click_me)
action.grid(column=1, row=1)
action.configure(state='disabled') # Disable the Button Widget

name_entered.focus_set() # Place cursor into name Entry

# Start GUI
window.mainloop()






组合框 Combo box widgets

下拉式组合框

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Modified Button click Event Function
def click_me():
action.configure(text='Hello ' + name.get()+ ' ' + number_chosen.get())

# Changing our Label
ttk.Label(window, text='Enter a name:').grid(column=0, row=0)

# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(window, width=12, textvariable=name)
name_entered.grid(column=0, row=1) # column 0

# Adding a Button
action = ttk.Button(window, text="Click Me!", command=click_me)
action.grid(column=2, row=1) # change column to 2

ttk.Label(window, text='Choose a number:').grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(window, width=12, textvariable=number)
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1) # Combobox in column 1
number_chosen.current(0)

name_entered.focus() # Place cursor into name Entry

# Start GUI
window.mainloop()


如果要限制用户,让他们只能选择程序中给出的选项,则要向构造器中传 Combobox 的 state 属性

[...]

number = tk.StringVar()
number_chosen = ttk.Combobox(window, width=12, textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1) # Combobox in column 1
number_chosen.current(0)

[...]




创建具有不同初始状态的复选按钮

Checkbutton
widgets

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Modified Button click Event Function
def click_me():
action.configure(text='Hello ' + name.get() + ' ' + number_chosen.get())

# Changing our Label
ttk.Label(window, text='Enter a name:').grid(column=0, row=0)

# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(window, width=12, textvariable=name)
name_entered.grid(column=0, row=1) # column 0

# Adding a Button
action = ttk.Button(window, text="Click Me!", command=click_me)
action.grid(column=2, row=1) # change column to 2

# Creating three checkbuttons
ttk.Label(window, text='Choose a number:').grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(window, width=12, textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1) # Combobox in column 1
number_chosen.current(0)

# Creating three checkbuttons
chVarDis = tk.IntVar()
check1 = tk.Checkbutton(window, text='Disabled', variable=chVarDis, state='disabled')
check1.select()
check1.grid(column=0, row=4, sticky=tk.W)

chVarUn = tk.IntVar()
check2 = tk.Checkbutton(window, text='UnChecked', variable=chVarUn)
check2.deselect()
check2.grid(column=1, row=4, sticky=tk.W)

chVarEn = tk.IntVar()
check3 = tk.Checkbutton(window, text='Enabled', variable=chVarEn)
check3.select()
check3.grid(column=2, row=4, sticky=tk.W)

name_entered.focus() # Place cursor into name Entry
# Start GUI
window.mainloop()




将网格的
sticky
属性设置为
tk.W
意味着该 widget 向网格的西(west)面对齐。

使用单选按钮 radio button widgets

Radiobutton
widgets

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Modified Button click Event Function
def click_me():
action.configure(text='Hello ' + name.get() + ' ' + number_chosen.get())

# Changing our Label
ttk.Label(window, text='Enter a name:').grid(column=0, row=0)

# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(window, width=12, textvariable=name)
name_entered.grid(column=0, row=1) # column 0

# Adding a Button
action = ttk.Button(window, text="Click Me!", command=click_me)
action.grid(column=2, row=1) # change column to 2

ttk.Label(window, text='Choose a number:').grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(window, width=12, textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1) # Combobox in column 1
number_chosen.current(0)

# Creating three checkbuttons
chVarDis = tk.IntVar()
check1 = tk.Checkbutton(window, text='Disabled', variable=chVarDis, state='disabled')
check1.select()
check1.grid(column=0, row=4, sticky=tk.W)

chVarUn = tk.IntVar()
check2 = tk.Checkbutton(window, text='UnChecked', variable=chVarUn)
check2.deselect()
check2.grid(column=1, row=4, sticky=tk.W)

chVarEn = tk.IntVar()
check3 = tk.Checkbutton(window, text='Enabled', variable=chVarEn)
check3.deselect()
check3.grid(column=2, row=4, sticky=tk.W)

# GUI callback function
def checkCallback(*ignoredArgs):
if chVarUn.get():
check3.configure(state='disabled')
else:
check3.configure(state='normal')
if chVarEn.get():
check2.configure(state='disabled')
else:
check2.configure(state='normal')

# trace the state of the two checkbutton
chVarUn.trace('w', lambda unused0, unused1, unused2 : checkCallback())
chVarEn.trace('w', lambda unused0, unused1, unused2 : checkCallback())

# Radiobutton Globals
COLOR1 = 'Blue'
COLOR2 = 'Gold'
COLOR3 = 'Red'

# Radiobutton Callback
def radCall():
radSel = radVar.get()
if radSel == 1:
window.configure(background=COLOR1)
elif radSel == 2:
window.configure(background=COLOR2)
elif radSel == 3:
window.configure(background=COLOR3)

# Create three Radiobuttons using one variable
radVar = tk.IntVar()

rad1 = tk.Radiobutton(window, text=COLOR1, variable=radVar,
value=1, command=radCall)
rad1.grid(column=0, row=5, sticky=tk.W, columnspan=3)

rad2 = tk.Radiobutton(window, text=COLOR2, variable=radVar,
value=2, command=radCall)
rad2.grid(column=1, row=5, sticky=tk.W, columnspan=3)

rad3 = tk.Radiobutton(window, text=COLOR3, variable=radVar,
value=3, command=radCall)
rad3.grid(column=2, row=5, sticky=tk.W, columnspan=3)

name_entered.focus() # Place cursor into name Entry
# Start GUI
window.mainloop()




使用滚动文本 scrolled text widgets

ScrolledText
要比简单的
Entry
大得多并且跨越多行。当文本大于 ScrolledText widget 的高度时,将自动启用垂直滚动条。

import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext

[...]

# Using a scrlled text control
scrol_w = 40
scrol_h = 3
scr = scrolledtext.ScrolledText(window, width=scrol_w, height=scrol_h, wrap=tk.WORD)
scr.grid(column=0, columnspan=3)

name_entered.focus() # Place cursor into name Entry
# Start GUI
window.mainloop()






通过将 wrap 属性设置为
tk.WORD
来告诉
ScrolledText
widget 通过单词来断行。 默认的是
tk.CHAR
,以字符来断行。

对于
ScrolledText
widget ,将网格的
columnspan
属性设置为 3,能够让该 widget 横跨 3 列。默认情况下只有 1 列。

重构

可以发现在上面的代码中有很多冗余,这里我们将重构它们。

#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext

# Create instance
window = tk.Tk()

# Add a title
window.title("My First Python GUI")

# Adding a Label that will get modified
a_label = ttk.Label(window, text = 'A Label')
a_label.grid(column=0, row=0)

# Modified Button click Event Function
def click_me():
action.configure(text='Hello ' + name.get() + ' ' + number_chosen.get())

# Changing our Label
ttk.Label(window, text='Enter a name:').grid(column=0, row=0)

# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(window, width=12, textvariable=name)
name_entered.grid(column=0, row=1) # column 0

# Adding a Button
action = ttk.Button(window, text="Click Me!", command=click_me)
action.grid(column=2, row=1) # change column to 2

ttk.Label(window, text='Choose a number:').grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(window, width=12, textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1) # Combobox in column 1
number_chosen.current(0)

# Creating three checkbuttons
chVarDis = tk.IntVar()
check1 = tk.Checkbutton(window, text='Disabled', variable=chVarDis, state='disabled')
check1.select()
check1.grid(column=0, row=4, sticky=tk.W)

chVarUn = tk.IntVar()
check2 = tk.Checkbutton(window, text='UnChecked', variable=chVarUn)
check2.deselect()
check2.grid(column=1, row=4, sticky=tk.W)

chVarEn = tk.IntVar()
check3 = tk.Checkbutton(window, text='Enabled', variable=chVarEn)
check3.deselect()
check3.grid(column=2, row=4, sticky=tk.W)

# GUI callback function
def checkCallback(*ignoredArgs):
if chVarUn.get():
check3.configure(state='disabled')
else:
check3.configure(state='normal')
if chVarEn.get():
check2.configure(state='disabled')
else:
check2.configure(state='normal')

# trace the state of the two checkbutton
chVarUn.trace('w', lambda unused0, unused1, unused2 : checkCallback())
chVarEn.trace('w', lambda unused0, unused1, unused2 : checkCallback())

# First, we change our Radiobutton globals variables into a list
colors = ['Blue', 'Gold', 'Red']

# We have also changed the callback function to be zero-based, using list
# instead of module-level global variables
# Radiobutton Callback
def radCall():
radSel = radVar.get()
if radSel == 1:
window.configure(background=colors[0]) # now zero-based and using list
elif radSel == 2:
window.configure(background=colors[1])
elif radSel == 3:
window.configure(background=colors[3])

# Create three Radiobuttons using one variable
radVar = tk.IntVar()

# Next we are selecting a non-existing index value for radVar
radVar.set(99)

# Now we are creating all three Radiobutton widgets within one loop
for col in range(3):
curRad = tk.Radiobutton(window, text=colors[col], variable=radVar,
value=col, command=radCall)
curRad.grid(column=col, row=5, sticky=tk.W)

# Using a scrlled text control
scrol_w = 40
scrol_h = 3
scr = scrolledtext.ScrolledText(window, width=scrol_w, height=scrol_h, wrap=tk.WORD)
scr.grid(column=0, columnspan=3)

name_entered.focus() # Place cursor into name Entry
# Start GUI
window.mainloop()


运行程序会发现和上面的一样,但代码更简洁清晰。

参考文献

Python GUI Programming Cookbook - Second Edition by Burkhard A. Meier
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python gui tkinter