zoukankan      html  css  js  c++  java
  • GUI的最终选择 Tkinter(九):事件

    Tkinter事件处理

    Tkinter应用会花费大部分的时间在处理事件循环中(通过mainloop()方法进入),事件可以是触发的鼠标,键盘的操作,管理窗口触发的重绘事件(在多数情况下都是有用户间接引起的)。

    Tkinter提供了一个强大的机制,可以让你自由的去处理事件,对于每个组件来说。可以通过bond()方法将函数或者方法绑定到具体的事件上。当触发器的事件满足该组件的事件时,Tkinter()就会带着事件取调用handler()方法。

    1 from tkinter import *
    2 
    3 root = Tk()
    4 def callbach(event):
    5     print("点击位置:",event.x,event.y)
    6 frame = Frame(root,width=200,height=200)
    7 frame.bind("<Button-1>",callbach)
    8 frame.pack()
    9 mainloop()

    执行结果:

    在例子中,使用Frame组件的bind()方法将鼠标的单击事件和自定义的callbach()方法绑定起来,那么运行的结果就是:当鼠标点击的时候,IDLE会相应的将鼠标的位置显示出来。

    只有当组件获得焦点的时候才能接收键盘事件(Key),下面的例子中将用focus_set()获得焦点,可以设置Frame的takefocus选项为True,然后将焦点转移上来。

     1 from tkinter import *
     2 
     3 root = Tk()
     4 def callbach(event):
     5     print("点击位置:",event.x,event.y)
     6 frame = Frame(root,width=200,height=200)
     7 frame.bind("<Key>",callbach)
     8 frame.focus_set()
     9 frame.pack()
    10 mainloop()

    执行结果:

    在来实现一个展示捕获鼠标轨迹的组件,需要关注的是事件。

    1 from tkinter import *
    2 
    3 root = Tk()
    4 def callbach(event):
    5     print("点击位置:",event.x,event.y)
    6 frame = Frame(root,width=200,height=200)
    7 frame.bind("<Motion>",callbach)
    8 frame.pack()
    9 mainloop()

    执行结果:

     

     

    事件序列

    Tkinter使用一种称之为事件序列的机制运行用户定义事件,用户需要使用bind()方法将具体的事件序列与自定义的方法做绑定。事件序列以字符串的形式表示的,可以是一个或多个相关联的事件(如果多个事件,需要对应的方法只有在满足所有事件的前提下才会满足)。

    事件序列使用一下语法描述:

    <modifier-type-detail>

    修饰 部分为可选内容,一般在组合事件中用于多功能按键组合的描述。如:Ctrl + Shift + V;

    类型 部分用于描述一般的事件对象类型,如键盘按键或鼠标动作等;

    type区域是事件说明符中最重要的部分,它说明我们想绑定哪一类的事件

    例如ButtonKey或者如进入、配置之类的窗口管理事件。

    详细描述 部分为可选内容,一般用于描述事件具体单元对象,如KeyPress-A,表示按键盘A键

    Modifier和detail区域用于额外的信息

    在许多情况下可以省略,还有各种方法来简化事件字符串,例如为了匹配键盘键,您可以省略

    尖括号,只需使用键,当然要包含在尖括号内让我们来看看最常见的事件格式

     

    事件格式

    <Button-1>鼠标左键按下事件,1表示左键;2-鼠标中键;3-鼠标右键

    当您在组件上按下鼠标左键,随后的鼠标事件(移动、释放)就会发送到当前组件,即使

    鼠标移动到当前组件之外,鼠标指针的的当前位置在传递给回调函数的event对象的x,y中

    <Button-1>、<ButtonPress-1>、<1>都是同义词

    <B1-Motion>按住鼠标左键移动鼠标,鼠标指针的当前位置在传递给回调函数的event中的xy提供

    <ButtonRelease-1>鼠标左键被释放

    <Double-Button-1>鼠标左键被双击,你可以用Double表示双击,还可以用Triple表示三击

    注意,如果你绑定了<Button-1>和<Double-Button-1>,那么2个事件都被触发

    键入部分常用的关键字及含义

    事件类型

    意义描述

    Activate

    组件状态变化事件,未激活变为激活时触发;

    与 Deactivate 相对

    Button

    鼠标按键点击事件;

    由描述部分指定具体按键:

      <Button-1> 鼠标左键

      <Button-2> 鼠标中键

      <Button-3> 鼠标右键

      <Button-4> 滚轮上(linux)

      <Button-5> 滚轮下(linux)

    ButtonRelease

    释放鼠标按键事件。强调释放动作

    Configure

    组件尺寸改变事件

    Deactivate

    组件状态改变事件。激活变为未激活;

    与 Activate 相对

    Destroy

    组件被销毁触发事件

    Enter

    鼠标指针进入组件区域事件;

    与 Leave 相对

    Expose

    窗口或组件的部分被显示时触发事件,比如某部分被置顶

    FocusIn

    获得焦点事件。如果组件的takefocus属性为True,则用户可通过Tab按键切换组件焦点。也可用focus_set()方法设置组件焦点

    FocusOut

    失去焦点事件

    KeyPress

    键盘按键事件。强调按下动作;

    由描述部分指定具体按键,如 <KeyPress-A>、<KeyPress-B>;

    可简写为Key

    KeyRelease

    释放键盘按键事件。强调释放动作

    Leave

    鼠标指针离开组件区域事件;

    与 Enter 相对

    Map

    组件被映射时触发事件。指在程序中,该组件被调用(组件显示、隐藏等)。如调用grid()方法

    Motion

    鼠标在组件区域内移动事件

    MouseWheel

    鼠标滚轮事件。该事件序列支持Windows和Mac 等同于Linux下的Button-4/5

    Unmap

    组件被取消映射事件;

    与Map相对

    Visibility

    应用程序至少有一部分被置顶(即被显示出来)事件

    <Shift-Up>

    用户按下shift键同时按下向上键触发,也可以用Alt,shift,control

    frame1.bind("<Shift M>",shiftm) 当同时按下shift 和m 后回调函数shiftm

    <Return>

    用户按下回车键,你可以绑定键盘上几乎所有键,Shift_L(左边的shift键)

    DeleteF1F5Num_Lock都可以

    修饰语

    修饰符

    意义

    Alt

    按下Alt键

    Any

    按下任意键。如<Any-KeyPress>,表示按下任意键事件

    Control

    按下Ctrl键

    Double

    被修饰的事件类型连续两次触发。如<Double-Button-1>,表示双击鼠标左键

    Lock

    大写字母锁定键

    Shift

    按下Shift

    Triple

    被修饰的事件类型连续三次触发

    事件对象

    当Tkinter回调预定义的函数时,将带着事件对象(作为参数)去掉用。

    事件对象的属性及含义

    属性

    意义描述

    widget

    产生事件的组件

    x,y

    以窗口左上角为原点,鼠标指针的坐标。以像素为单位

    x_root,y_root

    以屏幕左上角为原点,鼠标指针的坐标,以像素为单位

    char

    键盘按键字符

    keysym

    键盘按键名

    keycode

    键盘按键码

    num

    鼠标按钮数字

    width,height

    组件尺寸改变后的宽和高

    type

    事件类型

     

    当事件为,,的时候,细节可以通过设定具体的按键名来筛选,例如表示按下键盘的大写字母H的时候触发事件,表示按下键盘上的Tab键的时候触发事件。

    列举了键盘的所有特殊按键的keysym和keycode(其中的按键码是对应美国标准101键盘的latin-1字符集,键盘标准不同对应的按键码不同,但按键名是一样的。)

     

    键盘所有特殊按键的键符和键码

    按键名(keysym)

    按键码(keycode)

    按键描述

    Alt_L

    64

    左Alt

    Alt_R

    113

    右Alt

    BackSpace

    22

    退格

    Cancel

    110

    break键

    Caps_Lock

    66

    大写字母锁定

    Control_L

    37

    左Ctrl

    Control_R

    109

    右Ctrl

    Shift_L

    50

    左Shift

    Shift_R

    62

    右Shift

    Insert

    106

    插入键

    Delete

    107

    删除键

    Left

    100

    左方向键

    Right

    102

    右方向键

    Up

    98

    上方向键

    Down

    104

    下方向键

    Home

    97

    Home键

    End

    103

    End键

    Escape

    9

    Esc键

    Execute

    111

    Sysreq键

    F1~F11

    67~77

    F1键到F11键(一一对应)

    F12

    96

    F12键

    Linefeed

    54

    Linefeed键(Ctrl + J)

    KP_0

    90

    数字键盘0

    KP_1

    87

    数字键盘1

    KP_2

    88

    数字键盘2

    KP_3

    89

    数字键盘3

    KP_4

    83

    数字键盘4

    KP_5

    84

    数字键盘5

    KP_6

    85

    数字键盘6

    KP_7

    79

    数字键盘7

    KP_8

    80

    数字键盘8

    KP_9

    81

    数字键盘9

    KP_Subtract

    82

    数字键盘 -

    KP_Add

    86

    数字键盘 +

    KP_Begin

    84

    数字键盘中间键(5) 

    KP_Decimal

    91

    数字键盘点键

    KP_Delete

    91

    数字键盘删除

    KP_Divide

    112

    数字键盘反斜杠 /

    KP_Up

    80

    数字键盘上方向

    KP_Left

    83

    数字键盘左方向

    KP_Right

    85

    数字键盘右方向

    KP_Down

    88

    数字键盘下方向键

    KP_End

    87

    数字键盘End键

    KP_Enter

    108

    数字键盘回车

    KP_Home

    79

    数字键盘Home

    KP_Insert

    90

    数字键盘插入

    KP_Multiply

    63

    数字键盘星号 *

    KP_Next

    89

    数字键盘PageDown

    KP_Prior

    81

    数字键盘PageUp

    Next

    105

    PageDown键

    Num_Lock

    77

    数字键盘锁定

    Pause

    110

    Pause暂停

    Print

    111

    屏幕打印

    Prior

    99

    PageUp键

    Return

    36

    回车

    Scroll_Lock

    78

    ScrollLock键

    Tab

    23

    制表按键

    按键名(keysym)

    按键码(keycode)

    按键描述

    Alt_L

    64

    左Alt

    Alt_R

    113

    右Alt

    BackSpace

    22

    退格

    Cancel

    110

    break键

    Caps_Lock

    66

    大写字母锁定

    Control_L

    37

    左Ctrl

    Control_R

    109

    右Ctrl

    Shift_L

    50

    左Shift

    Shift_R

    62

    右Shift

     

    实例和类的绑定

    以上的例子中我们用的都是在实例上使用bind方法,这意味着这样只能bind在一个组件上,

    如果我们创建一个新的组件,他们不会继承这些绑定关系。

    不过Tkinter也提供了类级别和应用级别的bind,实际上,你可以使用以下级别的binding

    1.组件实例

    2.组件的顶层窗体(Toplevel 或者 root)

    3.组件类,用bind_class方法

    4.整个应用,用bind_all方法

    比如,你可以用bind_all来绑定F1按钮的点击,这样你能在这个应用的如何地方点击都可以弹出帮助框

    但如果同一个键你在多处绑定了怎么办?

    首先,在以上4个层次之内,Tkinter选择最接近匹配的方式。比如为<Key>

    和<Return>事件创建实例绑定,那么只有按下Enter键之后才会调用<Return>的回调函数

    但是,如果你如果在以上4个层次间,比如你同时向toplevel组件添加<Return>绑定,那么将调用2个绑定

    Tkinter首先调用实例级别的最佳绑定,最后在应用程序级别调用最佳可用绑定,因此,

    在极端情况下,单个事件可以调用4个事件处理程序。

    常见的混乱原因是当您尝试使用绑定来覆盖标准组件的默认行为。例如,假设你想在

    文本框内禁止输入回车键,这样用户就无法输入多行数据,也行你会用下面的小伎俩

    1 def ignore(event):
    2      pass
    3 
    4 text.bind("<Return>",ignore)

    或者,你喜欢一行的简洁代码

    text.bind("<Return>",lamdba e:None)

    不幸的是,新的一行依然会插入,因为,以上的绑定仅仅应用在应用级别,

    而标准的行为依然有类级别的绑定实现了。

    你可以使用bind_class方法来改变类级别的绑定,但这将更改应用程序中所有文本组件的行为。下面是比较合理的解决办法

    1 def ignore(event):
    2     return "break"
    3 text.bind("<Return>", ignore)

    顺便说一句,如果你真的想改变所有文本组件的默认行为,你可以用以下bind_class方法

    top.bind_class("Text", "<Return>", lambda e: None)

    真的不建议这么做,不要改变组件的默认行为。

    协议

    除了事件绑定,Tkinter还提供了协议处理的机制,这里的协议指的是应用程序和windows manager之间的互动

    最常见的是WM_DELETE_WINDOW,用于定义当用户使用窗口管理器显式关闭窗口是的事件。

    你可以用protocol方法来安装这个协议的回调函数(这个组件必须是root或者Toplevel组件)

    widget.protocol("WM_DELETE_WINDOW", handler)

    一旦你注册了自己的处理函数,Tkinter将不再自动的关闭程序,比如下面这个例子

    from Tkinter import *
    import tkMessageBox
    
    def callback():
        if tkMessageBox.askokcancel("Quit", "Do you really wish to quit?"):
            root.destroy()
    
    root = Tk()
    root.protocol("WM_DELETE_WINDOW", callback)
    root.mainloop()

    注意,即使你没有在顶层窗口注册WM_DELETE_WINDOW的处理程序,窗口还是会被销毁的。最好还是自己注册一个处理程序

    top = Toplevel(...)#确保窗口小部件实例被删除 
    top.protocol(“WM_DELETE_WINDOW”,top.destroy)
  • 相关阅读:
    死信队列消息原因排查
    MQ中间件死信队列深度不断增加问题解决案例
    DB2 57016报错的解决办法(表状态不正常,导致表无法操作)
    万门大学--童哲
    eclipse jvm配置
    weblogic threadpool has stuck threads
    8-10 ObserveableCommand演示
    8-9 四种执行方式区别讲解
    8-8 toObserve两种形态演示
    8-7 Observe两种形态演示
  • 原文地址:https://www.cnblogs.com/pinpin/p/10040771.html
Copyright © 2011-2022 走看看