Python进阶(二)-图形界面编程Tkinter(2)

二、图形界面编程

2.1 事件绑定

前面章节,我们了解了积木的形状(具体细节,例如每个组件都有哪些属性、方法我们一会儿在讲)、清理了我们搭建的平台(建立主窗口tk)、了解了怎么将积木拼接在一起(组件布局)。
但是有一点还不够完善,我们怎么跟我们拼接出来的东西互动呢?这就需要用到事件绑定,也叫事件处理。是程序用来接受用户的指令,并做出反应的过程。
事件处理,是 GUI 程序中不可或缺的重要组成部分,相比来说,控件只是组成一台机器的零部件, 而事件处理则是驱动这台机器“正常”运转的关键所在,它能够将零部件之间“优雅”的贯穿起来,因此“事件处理”可谓是 GUI 程序的“灵魂”,同时它也是实现人机交互的关键。
对于“事件”这一名词,在讲解控件时也偶尔提及过,在本节我们将对 Tkinter 中的事件处理机制做更为详细的介绍。

在一款 GUI 程序中,我们将用户对软件的操作统称为“事件”,比如鼠标点击按钮、键盘输入文本以及窗口管理器触发的重绘事件等,这些事件有一个共同的特点,即都是由用户直接或者间接触发的。
Tkinter为我们提供了两种事件绑定方法:

  1. 使用组件的command属性绑定处理函数(前面我们使用的按钮都使用的这种方式来与用户互动),这里就不在介绍
  2. 使用Widget组件的bind()方法,此方法更灵活,还可以获取事件的相关信息。
    其语法格式如下:
widget.bind("<event>",func)

上述语法中,widget 代表控件的实例对象,之后,采用 bind() 方法进行事件绑定,该函数有两个参数:
:一个字符串参数,表示事件的类型,并使用“尖括号”的形式进行包裹;
func:表示事件的处理函数(callback,即回调函数),当触发事件时,Tk 会携带事件对象(Event)去调用 func 方法。

注意:bind() 方法可以完成事件与处理函数绑定,而使用 unbind() 方法可以将事件与处理函数解绑。

2.1.1 事件码

事件类型(也称事件码)是 Tkinter 模块规定的,主要包括鼠标、键盘、光标等相关事件,Tkinter 为其规定了相应的语法格式:

<modifier-type-detail>

上述语法由三部分组成,说明如下:
<>:事件类型必须包含在“尖括号”内;
modifier:可选项,事件类型的修饰符,通常用于描述组合键、双击、大写锁定键以及等;
type:是必不可少的一项,表示事件的具体类型;
detail:可选项,通常用于描述具体的哪个按键,比如 表示鼠标左键;

这里有必要对经常使用的 modifier 修饰符做简单的介绍,修饰符可以修改事件的激活条件,比如双击鼠标或者需要同时按下某个键才触发事件,常用的修饰符如下:

修饰符 说明
Control 事件发生时需按下 Control 键
Alt 事件发生时需按下 Alt 键
Shift 事件发生时需按下 Shift 键
Lock 事件发生时需处于大写锁定状态
Double 事件连续发生两次,比如双击鼠标
Triple 事件连续发生三次
Quadruple 事件连续发生四次

下述表格中介绍了 Tkinter 中经常使用的事件类型,如下所示:

事件码 说明
单击鼠标左键,简写为,后面的数字可以是1/2/3,分别代表左键、中间滑轮、右键
释放鼠标左键,后面数字可以是1/2/3,分别代表释放左键、滑轮、右键
按住鼠标左键移动,和分别表示按住鼠标滑轮移动、右键移动
转动鼠标滑轮
双击鼠标左键
鼠标光标进入控件实例
鼠标光标离开控件实例
按下键盘上的任意键
<KeyPress-字母>/<KeyPress-数字> 按下键盘上的某一个字母或者数字键
释放键盘上的按键
回车键,其他同类型键有///
空格键
/// 方向键
常用的功能键
组合键,再比如,表示用户同时点击 Ctrl + Shift + T
当控件获取焦点时候触发,比如鼠标点击输入控件输入内容,可以调用 focus_set() 方法使控件获得焦点
当控件失去焦点时激活,比如当鼠标离开输入框的时候
控件的发生改变的时候触发事件,比如调整了控件的大小等
当控件的状态从“激活”变为“未激活”时触发事件
当控件被销毁的时候触发执行事件的函数
当窗口或组件的某部分不再被覆盖的时候触发事件
当应用程序至少有一部分在屏幕中是可见状态时触发事件

2.1.2 Event事件对象

当事件触发后,Tkinter 会自动将事件对象交给回调函数进行下步的处理,Event 对象包含了以下常用属性:

属性 说明
widget 发生事件的是哪一个控件
x,y 相对于窗口的左上角而言,当前鼠标的坐标位置
x_root,y_root 相对于屏幕的左上角而言,当前鼠标的坐标位置
char 用来显示所按键相对应的字符
keysym 按键名,比如 Control_L 表示左边的 Ctrl 按键
keycode 按键码,一个按键的数字编号,比如 Delete 按键码是107
num 1/2/3中的一个,表示点击了鼠标的哪个按键,按键分为左、中、右
width,height 控件的修改后的尺寸,对应着 事件
type 事件类型

下面看一组关于“键盘事件”的使用示例:

from tkinter import *
# 定义事件函数,必须用event参数
def show_key(event):
    # 查看触发事件的按钮
    s=event.keysym
    # 将其显示在按钮控件上
    lb.config(text=s)
root=Tk()
root.config(bg='#87CEEB')
root.title("Python学习")
root.geometry('450x350+300+200')
root.iconbitmap('C:/Users/Administrator/Desktop/logo.ico')
# 添加一个按钮控件
lb=Label(root,text='请按键',fg='blue',font=('微软雅黑',15))
# 给按钮控件绑定事件,按下任意键,然后调用事件处理函数。注意,此处需要在英文状态下进行输入
lb.bind('<Key>',show_key)
# 设置按钮获取焦点
lb.focus_set()
lb.pack()
# 显示窗口
root.mainloop()

注意:在上述示例中,只有当 Label 控件获取焦点后才能接收键盘事件,因此在给控件绑定事件和回调函数后,需要使用 focus_set() 方法来获取焦点。

下面再看一组关于“鼠标事件”的相关示例:

# 定义事件函数
from tkinter import *
def handleMotion(event):
    lb1['text'] = '你移动了光标的所在位置'
    lb2['text'] = '目前光标位置:x ='+ str(event.x)+';y='+str(event.y)
    print('光标当前位置',event.x,event.y)
# 创建主窗口
win = Tk()
win.config(bg='#87CEEB')
win.title("Python学习")
win.geometry('450x350+300+200')
win.iconbitmap('C:/Users/Administrator/Desktop/logo.ico')
# 创建一个窗体容器frame
frame = Frame (win, relief=RAISED, borderwidth=2, width=300,height=200)
frame.bind('<Motion>',handleMotion)
lb1 = Label(frame,text='没有任何事件触发', bg='purple', )
# 使用place进行位置布局,下一节会介绍
lb1.place (x=20,y=20)
lb2 = Label(frame,text='')
lb2.place (x=16,y=60)
frame.pack(side=TOP)
# 显示窗口
win.mainloop()

2.2 组件介绍

组件是构成用户界面的基本元素,前面我们讲解了组件的一些通用属性,下面详细讲解各个组件的属性、方法。

2.2.1 组件支持的两个特殊类

在讲解组件之前,先了解两个组件中会用到的两个重要属性,Variable和compound,特别是用于组件内容的显示。

2.2.1.1 Variable类

我们设想一下,如果一个组件的内容经常发生改变,难道我们要重复的对组件内容进行赋值吗?我们能不能使用一个变量来给组件赋值呢?答案是肯定的,就需要使用Variable变量,因为组件的内容是不允许与普通变量绑定的,只能使用tkinter包下的Variable类的子类进行绑定。这个过程也叫做双向绑定,下表列出了Variable类的子类:

子类 说明
StringVar() str值得变量
IntVar() 整型值变量
DoubleVar() 浮点值
BooleanVar() bool值

Variable类包含了2个方法:

  • set():设置变量值
  • get():获取变量值

在界面编程的过程中,有时我们需要“动态跟踪”一些变量值的变化,从而保证值的变换及时的反映到显示界面上,但是 Python 内置的数据类型是无法这一目的的,因此使用了 Tcl 内置的对象,我们把这些方法创建的数据类型称为“动态类型”,比如 StringVar() 创建的字符串,称为“动态字符串”。

下面示例程序示范了将Entry组件与StrinVar进行双向绑定,这样车徐既可以通过该StringVar改变Entry输入框显示内容,也可通过该StringVar获取Entry输入框中的内容。

from tkinter import  *
from tkinter import ttk

class App:
    def __init__(self,master):
        self.master = master
        self.iniWidgets()
    def initWidgets(self)
        self.st = StringVar() #定义Variable子类StringVar
        ttk.Entry(self.master,textvariable=self.st,width=24,font=('StSong',20,'bold'),foreground='red').pack(file=BOTH,expand=YES)
        #创建Entry组件,将其textvariable绑定到self.st变量
        f = Frame(self.master).pack()
        b1=ttk.Button(f,text='改变').pack(side=LEFT)
        b2=ttk.Button(f,text='获取').pack(side=LEFT)
        #创建两个按钮
        b1.bind('<ButtonPress-1>',self.change)
        b2.bind('<ButtonPress-1>',self.get)
    def change(self,event)
        languages = ('C','C++','JAVA','Python','JS')
        import random
        self.st.set(languages[random.randint(0,4)])
        # 使用set()方法设置st,与之绑定的Enter内容也随之改变
    def get(self,event)
        from tkinter import messagesbox
        messagesbox.showinfo(title='输入内容',message=self.st.get())
        #使用get()方法获取st内容,即Entry组件内容
window = Tk()
Window.title('variable测试')
App(Window)
Window.mainloop()

程序说明已经在程序内以注释形式给出。

2.2.1.2 compound属性

按钮或Lable等组件同时有text、image两个选项,当两个选项同时指定时,通常image会覆盖text,如果希望同时像是文本和图片,就需要使用compound选项进行控制。
compound选项支持的属性值如下:

  • None:图片覆盖文字
  • LEFT常量(值为‘left’字符串):图片在左,文本在右
  • RIGHT常量(值为‘right’字符串):图片在右,文本在左
  • TOP常量(值为‘top’字符串):图片在上,文本在下
  • BOTTOM常量(值为‘bottom’字符串):图片在底,文本在上
  • CENTER常量(值为‘center’字符串):文字覆盖在图片上方

下面通过一个程序示例,来改变compound的值:

from tkinter import *
from tkinter import ttk
class App:
    def __init__(self,master):
        self.master = master
        self.initWidgets():
    def initWidgets(self):
        bm = PhotoImage(file='serial.png')  
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值