Python Chapter 9: 使用Tkinter进行GUI程序设计 Part 4

10. 弹出菜单

 1 # Program 9.14
 2 from tkinter import *
 3 
 4 class PopupMenuDemo:
 5     def __init__(self):
 6         window = Tk()
 7         window.title("Popup Menu Demo")
 8 
 9         self.menu = Menu(window, tearoff = 0)
10         self.menu.add_command(label = "Draw a line", command = self.displayLine)
11         self.menu.add_command(label = "Draw an oval", command = self.displayOval)
12         self.menu.add_command(label = "Draw a rectangle", command = self.displayRect)
13         self.menu.add_command(label = "Clear", command = self.clearCanvas)
14 
15         self.canvas = Canvas(window, width = 200, height = 100, bg = "white")
16         self.canvas.pack()
17 
18         self.canvas.bind("<Button-3>", self.popup)
19 
20         window.mainloop()
21 
22     def displayRect(self):
23         self.canvas.create_rectangle(10, 10, 190, 90, tags = "rect")
24 
25     def displayOval(self):
26         self.canvas.create_oval(10, 10, 190, 90, tags = "oval")
27 
28     def displayLine(self):
29         self.canvas.create_line(10, 10, 190, 90, tags = "line")
30         self.canvas.create_line(10, 90, 190, 10, tags = "line")
31 
32     def clearCanvas(self):
33         self.canvas.delete("rect", "oval", "line")
34 
35     def popup(self, event):
36         self.menu.post(event.x_root, event.y_root)
37 
38 PopupMenuDemo()

9-13) 用self.menu存储Menu类对象是因为后续方法中会需要访问此menu,故将其放在类的数据域中

   self.menu.add_command(label, command)给一个菜单栏添加具体命令

18) self.canvas.bind(string, command)将对象self.canvas与命令command绑定起来,调用此回调函数的条件由string描述,此处"<Button-3>"代表当在Canvas内点击鼠标右键时(更多的string选项在后续的章节中进行介绍)

36) 当在self.canvas中点击鼠标右键会调用popup()函数,其中self.menu.post(x, y)将菜单menu显示在坐标为(x, y)的地方,此处event代表事件对象(此处即为点击鼠标右键),event.x_root与event.y_root分别代表此事件发生的x坐标与y坐标(此处即为在画布中点击右键处的x,y坐标)。menu.post(x, y)是设计弹出菜单的关键

11. 鼠标、按键事件和绑定

前面例子使用小构件的bind方法将事件与回调处理器绑定:

widget.bind(event, handler)

其中event所代表的的事件应用引号括起来表示成字符串,具体事件有以下选项:

事件 描述
<Bi-Motion> 当鼠标左键按住小构件且移动鼠标时事件发生
<Button-i> Button-1、Button-2、Button-3分别表明左键、中键和右键,单击时触发事件,且Tkinter会自动抓取鼠标指针的位置
<ButtonReleased-i>

当释放鼠标左中右键时触发事件

<Double-Button-i> 当双击鼠标左中右键时触发事件
<Enter> 当鼠标光标进入小构件时触发事件
<Key> 当单机一个键时触发事件
<Leave> 当鼠标光标离开小构件时事件发生
<Return> 当单机“Enter”键时事件发生,此处亦可将Return替换为键盘上的任意键("A"、"B"、"Down“、“Right”等)
<Shift+A> 当单机"Shift+A"键时事件发生,可以将Alt、Shift、Control和其他键任意组合
<Triple-Button-i> 当三次单机鼠标左中右键时事件发生

与此同时,每个事件也对应了诸多属性,采用event.properties调用这些属性值:

事件属性 描述
char 对<Key>事件有效,得到从键盘输入的字符
keycode 对<Key>事件有效,得到从键盘输入字符的统一码(有时是ASCII码)
keysym 对<Key>事件有效,得到从键盘输入字符的符号(其实就是字符)
num num=1/2/3表示按下的是鼠标哪个键
widget 触发这个事件的小构件对象
x、y 当前鼠标在小构件中以像素为单位的位置
x_root、y_root 当前鼠标相对于屏幕左上角的以像素为单位的位置

下面是一个使用小构件绑定事件及事件属性的例子:

 1 # Program 9.15
 2 from tkinter import *
 3 
 4 class MouseKeyEventDemo:
 5     def __init__(self):
 6         window = Tk()
 7         window.title("Event Demo")
 8         canvas = Canvas(window, bg = "white", width = 200, height = 100)
 9         canvas.pack()
10 
11         canvas.bind("<Button-1>", self.processMouseEvent)
12 
13         canvas.bind("<Key>", self.processKeyEvent)
14         canvas.focus_set()
15 
16         window.mainloop()
17 
18     def processMouseEvent(self, event):
19         print("clicked at ", event.x, event.y)
20         print("Position in the screen", event.x_root, event.y_root)
21         print("Which button is clicked? ", event.num)
22 
23     def processKeyEvent(self, event):
24         print("keysym? ", event.keysym)
25         print("char? ", event.char)
26         print("keycode? ", event.keycode)
27 
28 MouseKeyEventDemo()

11)将canvas绑定<Button-1>即左键点击事件并调用processMouseEvent方法

13)将canvas绑定<Key>即键盘输入事件并调用processKeyEvent方法

14)canvas.focus_set()在画布上设置焦点从而从键盘上获取输入(其实我心里是???焦点跟这有啥关系)

19-21、24-26) 调用了event事件的x/y/x_root/y_root/num/keysym/char/keycode等一系列属性

 1 # Program 9.16
 2 from tkinter import *
 3 
 4 class EnlargeShrinkCircle:
 5     def __init__(self):
 6         self.radius = 50
 7 
 8         window = Tk()
 9         window.title("Control Circle Demo")
10         self.canvas = Canvas(window, bg = "white", width = 200, height = 200)
11         self.canvas.pack()
12         self.canvas.create_oval(100 - self.radius, 100 - self.radius, 100 + self.radius, 100 + self.radius, tags = "oval")
13 
14         self.canvas.bind("<Button-1>", self.increaseCircle)
15         self.canvas.bind("<Button-3>", self.decreaseCircle)
16 
17         window.mainloop()
18 
19     def increaseCircle(self, event):
20         self.canvas.delete("oval")
21         if self.radius < 100:
22             self.radius += 2
23         self.canvas.create_oval(100 - self.radius, 100 - self.radius, 100 + self.radius, 100 + self.radius, tags = "oval")
24 
25     def decreaseCircle(self, event):
26         self.canvas.delete("oval")
27         if self.radius > 2:
28             self.radius -= 2
29         self.canvas.create_oval(100 - self.radius, 100 - self.radius, 100 + self.radius, 100 + self.radius, tags = "oval")
30 
31 EnlargeShrinkCircle()

14-15) 添加点击鼠标左键、右键事件至self.canvas,并分别与increaseCircle和decreaseCircle方法绑定

19-29) 在increaseCircle与decreaseCircle中,先调用canvas对象的delete方法清除原先的圆,再更改self.radius更新半径,最后重新调用canvas对象create_oval方法绘制新的圆

12. 动画

 1 # Program 9.17
 2 from tkinter import *
 3 
 4 class AnimationDemo:
 5     def __init__(self):
 6         window = Tk()
 7         window.title("Animation Demo")
 8 
 9         width = 250
10         canvas = Canvas(window, bg = "white", width = 250, height = 50)
11         canvas.pack()
12 
13         x = 0
14         canvas.create_text(x, 30, text = "Message moving?", tags = "text")
15 
16         dx = 3
17         while True:
18             canvas.move("text", dx, 0)
19             canvas.after(100)
20             canvas.update()
21             if x < width:
22                 x += dx
23             else:
24                 x = 0
25                 canvas.delete("text")
26                 canvas.create_text(x, 30, text = "Message moving?", tags = "text")
27 
28         window.mainloop()
29 
30 AnimationDemo()

14) 调用canvas对象的create_text方法,create_text(x, y, text, tags)其中x, y为创建消息的坐标,text为消息内容,tags为其标签

18) 调用canvas对象的move方法,move(tags, dx, dy)其中tags为待移动的标签,dx为横向的坐标移动值(右正左负),dy为纵向的坐标移动值(下正上负)

19-20) canvas.after(100)使程序暂停100ms,canvas.update()重新显示画布

21-26) 通过变量x监测消息的当前位置,若超过width则将原消息删掉,在初始位置新建消息并更新变量x=0

 1 # Program 9.18
 2 from tkinter import *
 3 
 4 class ControlAnimation:
 5     def __init__(self):
 6         window = Tk()
 7         window.title("Control Animation Demo")
 8 
 9         self.width = 250
10         self.canvas = Canvas(window, bg = "white", width = self.width, height = 50)
11         self.canvas.pack()
12 
13         frame = Frame(window)
14         frame.pack()
15         btStop = Button(frame, text = "Stop", command = self.stop)
16         btStop.pack(side = LEFT)
17         btResume = Button(frame, text = "Resume", command = self.resume)
18         btResume.pack(side = LEFT)
19         btFaster = Button(frame, text = "Faster", command = self.faster)
20         btFaster.pack(side = LEFT)
21         btSlower = Button(frame, text = "Slower", command = self.slower)
22         btSlower.pack(side = LEFT)
23 
24         self.x = 0
25         self.sleepTime = 100
26         self.canvas.create_text(self.x, 30, text = "Message moving?", tags = "text")
27 
28         self.dx = 3
29         self.isStopped = False
30         self.animate()
31 
32         window.mainloop()
33 
34     def stop(self):
35         self.isStopped = True
36 
37     def resume(self):
38         self.isStopped = False
39         self.animate()
40 
41     def faster(self):
42         if self.sleepTime > 5:
43             self.sleepTime -= 20
44 
45     def slower(self):
46         self.sleepTime += 20
47 
48     def animate(self):
49         while not self.isStopped:
50             self.canvas.move("text", self.dx, 0)
51             self.canvas.after(self.sleepTime)
52             self.canvas.update()
53             if self.x < self.width:
54                 self.x += self.dx
55             else:
56                 self.x = 0
57                 self.canvas.delete("text")
58                 self.canvas.create_text(self.x, 30, text = "Message moving?", tags = "text")
59 
60 ControlAnimation()

25) 将移动的间隔时间声明为self.sleepTime,方便后续方法中访问这个值

15-22) 新建四个按钮,分别绑定四个方法,从而实现消息移动的停止、继续、加速、减速功能

29) self.isStopped 参数决定图像是否继续移动,这一点在animate()方法中的while not self.isStopped中凸显出来

48-58)self.animate()是整个程序的核心,负责消息的移动

13. 滚动条

 1 # Program 9.19
 2 from tkinter import *
 3 
 4 class ScrollText:
 5     def __init__(self):
 6         window = Tk()
 7         window.title("Scroll Text Demo")
 8 
 9         frame1 = Frame(window)
10         frame1.pack()
11         scrollbar = Scrollbar(frame1)
12         scrollbar.pack(side = LEFT, fill = Y)
13         text = Text(frame1, width = 40, height = 10, wrap = WORD, yscrollcommand = scrollbar.set)
14         text.pack()
15         scrollbar.config(command = text.yview)
16 
17         window.mainloop()
18 
19 ScrollText()

11) 创建一个Scrollbar对象,其父容器为frame1

12) 将scrollbar放在文本的左端

13) 新建一个文本对象Text(frame, width, height, wrap, yscrollcommand),其中yscrollcommand填Scrollbar对象.set,即可将此文本与滚动条对象绑定

15) scrollbar.config(command),其中command为text.yview,将文本对象与滚动条绑定为纵向滑动

其运行结果如下图:

14. 标准对话框

 1 # Program 9.20
 2 import tkinter.messagebox
 3 import tkinter.simpledialog
 4 import tkinter.colorchooser
 5 
 6 tkinter.messagebox.showinfo("showinfo", "This is an info msg")
 7 
 8 tkinter.messagebox.showwarning("showwarning", "This is a warning")
 9 
10 tkinter.messagebox.showerror("showerror", "This is an error")
11 
12 isYes = tkinter.messagebox.askyesno("askyesno", "Continue?")
13 print(isYes)
14 
15 isOK = tkinter.messagebox.askokcancel("askokcancel", "OK?")
16 print(isOK)
17 
18 isYesNoCancel = tkinter.messagebox.askyesnocancel("askyesnocancel", "Yes, No, Cancel?")
19 print(isYesNoCancel)
20 
21 name = tkinter.simpledialog.askstring("askstring", "Enter your name")
22 print(name)
23 
24 age = tkinter.simpledialog.askinteger("askinteger", "Enter your age")
25 print(age)
26 
27 weight = tkinter.simpledialog.askfloat("askfloat", "Enter your weight")
28 print(weight)

2-4) 弹窗的一些模块,使用时需要import

6-10) tkinter.messagebox.show(info/warning/error)(str1, str2) 创建信息/警告/错误弹窗,其中str1为该弹窗标题,str2为该弹窗的内容,三种不同的弹窗还会配上系统为信息/警告/错误预置的图标

12-18) tkinter.messagebox.ask(yesno/okcancel/yesnocalcel) (str1, str2)创建三种类型的弹窗,且皆有返回值。当三个例子中点击(yes/ok/yes)时返回值为True,当三个例子中点击(no/cancel/no)时返回值为False,当在第三个例子中点击cancel时返回值为None(python中类似null的东西)

21-28) tkinter.simpledialog.ask(string/integer/float) 创建三种类型弹窗,其中包含一输入框分别向用户请求一个字符串/整数/浮点数,返回值即为用户输入的内容,若用户点击了Cancel则返回值为None

所有对话框都是模态窗口,意味着对话框消失程序将不再继续(??不懂)

第9章 使用Tkinter进行GUI程序设计 到此结束

猜你喜欢

转载自www.cnblogs.com/fsbblogs/p/9695880.html
今日推荐