程序设计思想与方法 (5a) 图形界面编程
DESCRIPTION
程序设计思想与方法 (5a) 图形界面编程. 赵 海 计算机科学与工程系 上海交通大学 zhaohai @cs.sjtu.edu.cn. 学习目标. 理解对象的概念,以及它如何能用于简化编程。 熟悉图形库 ( 模块 ) 中的各种对象。 能在编程中创建对象并调用合适的方法完成图形计算。. 学习目标. 理解计算机图形学的基础概念,特别是坐标系统和坐标变换 。 在图形编程中,理解如何使用鼠标和文本输入。 能够用图形库编写简单的交互图形程序。. 概要. 每种数据类型能代表一组值,并且具备一组关联的操作运算。 传统的编程观点认为,数据是被动的,它由主动的操作运算来控制。. - PowerPoint PPT PresentationTRANSCRIPT
1
程序设计思想与方法 (5a)
图形界面编程赵 海
计算机科学与工程系上海交通大学
2
学习目标• 理解对象的概念,以及它如何能用于简化
编程。• 熟悉图形库 ( 模块 ) 中的各种对象。• 能在编程中创建对象并调用合适的方法完
成图形计算。
3
学习目标• 理解计算机图形学的基础概念,特别是坐
标系统和坐标变换 。• 在图形编程中,理解如何使用鼠标和文本
输入。• 能够用图形库编写简单的交互图形程序。
4
概要• 每种数据类型能代表一组值,并且具备一
组关联的操作运算。• 传统的编程观点认为,数据是被动的,它
由主动的操作运算来控制。
5
概要• 现代计算机程序使用面向对象的 (object-oriented)
方法来构建。• 你熟悉的应用程序都具有图形用户界面 ( 接口 ) (
Graphical User Interfaces , GUI ),提供视窗、图标、按钮和菜单等元素。
• 本教材专门提供一个图形库 (graphics.py) ,它基于 Tkinter 书写 .
6
对象 (objects) 的目的、作用• 基本思路 – 视一个复杂系统为一些简单对
象的交互。一个对象是一类活跃的数据类型,它结合了数据和上面的操作。
• 对象知道一些事情 ( 包含数据 ) ,并且,它能做一些事情 ( 具备操作 ).
• [ 图形 ] 对象之间的交互通过彼此发送消息( messages )来实现。
7
对象 (objects) 的目的• 假定我们要给一个大学开发一个数据处理
系统。• 我们需要维护入学的学生的纪录。每个学
生可以表示为一个对象。
8
对象 (objects) 的目的• 学生对象将包含如下数据 :
– 姓名– 学生证号– 选修的课程– 宿舍地址– 家庭地址– GPA– 等等 .
9
对象 (objects) 的目的• 学生对象应能对处理请求作出相应。• 我们可能想发出一个全校范围的邮件,因此,我
们需要每个学生的宿舍地址。• 我们能发送 printCampusAddress 消息给每
个学生对象。 当学生对象接到这个消息后,它能打印自己的地址。
10
对象 (objects) 的目的• 对象可以引用其它对象。• 每个课程可以表示为一个对象 :
– 授课教师– 学生名单– 先修课程– 上课时间和地点
11
对象 (objects) 的目的• 操作示例
– addStudent– delStudent– changeRoom–等等
12
简单的图形编程• 使用图形库 graphics.py 。• 图形库的位置:
– Python 的库目录(文件夹),和其它库文件在一起。
– 和你的图形程序在同一目录。
13
简单的图形编程• 我们首先需要按照模块导入这个库>>> import graphics
• 一个图形窗口是一个屏幕区域,所要展现的图形将出现其中。>>> win = graphics.GraphWin()
• 该命令生成一个新的窗口,题为 “ Graphics Window.”
14
简单的图形编程• GraphWin 是一个分配给变量 win 的对象。
我们能通过这个变量来操作这个对象,类似于通过文件句柄来操作文件。
• 窗口能被如下的命令关闭或者销毁 >>> win.close()
15
简单的图形界面编程
16
简单的图形界面编程• 每次调用图形库中的函数都要使用标识graphics. 是一件很麻烦的事
• from graphics import *“from” 命令允许你从模块库中加载相应的函数。 “ *” 是加载所有函数;或者你也可以选择加载自己指定的函数 .
17
简单的图形界面编程• 像这样使用 import 命令可以消除在调用图形库函
数之前一定要添加的前缀标识 graphics.>>> from graphics import *>>> win = GraphWin()
18
简单的图形界面编程• 一个图形界面窗口是由像素点组成的 ,像素是图
形的基本组成要素。• 默认的 GraphWin 是 200 像素高, 200 像素宽
( 一共 40,000).• 一个在窗口中绘制图形的方法就是一次画一个像
素点。但是这太麻烦了,图形库有很多事先定义好的函数可以直接绘制几何图形。
19
简单的图形界面编程• 最简单的对象是 Point 。与几何中的点的表示一
样 , 点的坐标由坐标系统 (x, y) 表示 , 其中 x 是横坐标, y 是纵坐标 .
• 图形窗口中的原点 (0,0) 在窗口的左上角 .• X 的值从左往右增大 , y 的值从上往下增大 .• 右下角的坐标是 (199, 199)
20
简单的图形界面编程>>> p = Point(50, 60)
>>> p.getX()
50
>>> p.getY()
60
>>> win = GraphWin()
>>> p.draw(win)
>>> p2 = Point(140, 100)
>>> p2.draw(win)
21
简单的图形界面编程>>> ### 打开一个图形窗口>>> win = GraphWin('Shapes')>>> ### 绘制一个圆点在 (100, 100)半径是 30 的红色的圆>>> center = Point(100, 100)>>> circ = Circle(center, 30)>>> circ.setFill('red')>>> circ.draw(win)>>> ### 在圆的中心绘制一个文字标签>>> label = Text(center, "Red Circle")>>> label.draw(win)>>> ### 使用 Rectangle 对象绘制一个正方形>>> rect = Rectangle(Point(30, 30), Point(70, 70))>>> rect.draw(win)>>> ### 使用 Line 对象绘制一条线段>>> line = Line(Point(20, 30), Point(180, 165))>>> line.draw(win)>>> ### 使用 Oval绘制一个椭圆>>> oval = Oval(Point(20, 150), Point(180, 199))>>> oval.draw(win)
22
使用图形对象• 系统通过让对象执行它相应的函数来实现
相应的功能 .
• 在前一个例子中,我们使用了 GraphWin, Point, Circle, Oval, Line, Text 以及 Rectangle. 它们向我们展示了这些类是如何使用的 .
23
使用图形对象• 每一个对象都是一个类的实例,这个类描述了这个实例的特性。
• 如果我们说 Augie 是一条狗 , 我们实际上是在说 Augie 狗这个大类中的一个特定的个体 . Augie 是狗这个类的一个实例。
24
使用图形对象• 我们使用一个特定的操作称为构造函数
(constructor) 来新创建一个类的实例 .<class-name>(<param1>, <param2>, …)
• <class-name> 是我们想要构建的实例的类的名字 , 例如 . Circle 或者 Point.
• 参数是用来初始化这个对象用的。例如: Point 需要两个数字参数
25
使用图形对象• p = Point(50, 60)
Point 类的构造函数需要两个参数,点的 x与 y 坐标 .
• 这些值会作为实例变量存储在对象中 .
26
使用图形对象• 这里只展示了最相关的实例变量(其它的还包括颜色,父窗口等等暂时隐藏)
27
使用图形对象• 要让对象执行操作,我们需要给对象传递一个信
息,而一个对象可以响应的所有的信息集合称作这个对象的方法 (Method) .
• 方法就好比对象内部的函数• 你可以通过“点”来调用方法 :
<object>.<method-name>(<param1>, <param2>, …)
28
使用图形对象• p.getX() 与 p.getY() 返回一个点的 x与y 的值 . 像这种常规方法被称为访问方法(accessors) ,因为它们可以获取对象中的实例变量信息 .
29
使用图形对象• 其它的方法通过改变对象的实例变量的值来改变
对象的状态 .• move(dx, dy) 把对象在 x 方向上移动 dx 个单位在 y
方向上移动 dy 个单位 .• Move 操作擦除了老的图像,然后在新位置上绘制
一个新图像 . 像这种改变对象状态的方法称为修改方法 (mutators).
30
使用图形对象>>> circ = Circle(Point(100, 100), 30)>>> win = GraphWin()>>> circ.draw(win)
• 第一行创建了一个半径 30 ,圆点在 (100,100) 的圆 .
• 我们使用 Point 构造函数为这个圆的中心创建了一个点 .
• 最后一行是 Circle 对象 circ 在 GraphWin 对象win 中绘制它自己 .
31
使用图形对象• draw 方法会使用实例
变量,获取圆点、半径信息 .
32
使用图形对象• 两个不同的变量指向同一个对象是可以的——这
时对其中一个变量的修改会直接同步影响到另一个变量>>> leftEye = Circle(Point(80,50), 5)>>> leftEye.setFill('yellow')>>> leftEye.setOutline('red')>>> rightEye = leftEye>>> rightEye.move(20,0)
• 这段代码的想法是首先创建一个左眼对象,然后把它拷贝给右眼对象,然后移动右眼对象 20 个单位 ( 相当于画两只眼睛,可惜它没有成功 ).
33
使用图形对象• 赋值语句 rightEye = leftEye 让左眼与右眼都指向了同一个 circle 对象!
• 像这种两个变量都指向同一个对象的情形,成为别名 (aliasing).
34
使用图形对象
35
使用图形对象• 有两种方法可以解决这个别名问题 .• 我们可以绘制两个圆 circles, 给两个眼睛分
别画一个 :>>> leftEye = Circle(Point(80, 50), 5)>>> leftEye.setFill('yellow')>>> leftEye.setOutline('red')>>> rightEye = Circle(Point(100, 50), 5)>>> rightEye.setFill('yellow')>>> rightEye.setOutline('red')
36
使用图形对象• 图形库里有个更好的解决办法 . 图形对象
有一个拷贝方法 (clone) ,可以拷贝该对象>>> # Correct way to create two circles, using clone>>> leftEye = Circle(Point(80, 50), 5)>>> leftEye.setFill('yellow')>>> leftEye.setOutline('red')>>> rightEye = leftEye.clone() # rightEye is an exact copy of the left>>> rightEye.move(20, 0)
37
数据绘制 /选择坐标
win = GraphWin("Investment Growth Chart", 320, 240)
win.setCoords(-1.75,-200, 11.5, 10400)
38
可交互的图形界面• 在图形界面环境中,用户通常通过点击按
钮、选择菜单选项、在输入框中输入文字来实现与程序的交互 .
• 事件驱动 (Event-driven) 程序在屏幕上绘制交互元素 (小插件 /widgets) ,然后等待用户操作 .
39
可交互的图形界面• 当用户移动鼠标、点击鼠标或者敲打键盘
是,一个事件 (event)就产生了 .• 事件是一个对象,它封装了刚刚发生的事
件的信息• 事件对象会被送给程序的相应部分进行处
理,比如按钮事件 (button event).
40
可交互的图形界面• 图形操作模块隐藏了底层的窗口操作管理,只在 GraphWin 中提供了两个简单的方法来获取用户输入 .
41
获取鼠标点击• 我们可以通过调用 GraphWin 类中的 getMouse
方法来获取图形信息 .• 当 GraphWin 中的 getMouse 被调用时 , 程序暂停运行,然后等待用户在窗口中的某处点击鼠标 .
• 用户点击的地方的信息会封装成 Point返回 .
42
获取鼠标点击• 这段代码可以打印鼠标点击的坐标 :
from graphics import *win = GraphWin("Click Me!")p = win.getMouse()print "You clicked (%d, %d)" % (p.getX(), p.getY())
• 对于返回的 point 的操作,我们可以使用访问方法例如 getX 以及 getY 或者其他的方法 .
43
获取鼠标点击# triangle.pyw# 用可交互的图形编程来画一个三角形
from graphics import *
def main(): win = GraphWin("画一个三角形 ") win.setCoords(0.0, 0.0, 10.0, 10.0) message = Text(Point(5, 0.5), " 请点三个点 ") message.draw(win)
# 获取并绘制三角形的三个顶点 p1 = win.getMouse() p1.draw(win) p2 = win.getMouse() p2.draw(win) p3 = win.getMouse() p3.draw(win)
44
获取鼠标点击# 使用多边形对象来绘制三角形 triangle = Polygon(p1,p2,p3)
triangle.setFill("peachpuff")
triangle.setOutline("cyan")
triangle.draw(win)
# 等待再一次点击推出程序 message.setText("随便点击推出程序 .")
win.getMouse()
main()
45
获取鼠标点击
46
获取鼠标点击• 注意 :
– 当你在 windows环境下编程时 , 如果你使用 .pyw 后缀,双击运行你的 python 程序时, Python 的 shell 窗口不会显示出来 .
– 没有三角形类,所以我使用了更一般的多边形类,这个类可以把任意多的点连接成一个封闭图形 .
47
获取鼠标点击– 一旦你获取了三个点 , 创建一个三角形就很容易了 :
triangle = Polygon(p1, p2, p3)
– 在程序的开始处创建并绘制一个文本对象 .message = Text(Point(5,0.5), “Click on three points”)message.draw(win)
– 要改变提示,只要修改要展示的文字即可message.setText(“Click anywhere to quit.”)
48
处理文字输入• 这个三角形程序的输入完全靠鼠标点击 . 这里还
有一个 Entry 对象可以获取键盘输入 .• Entry 对象能在屏幕上绘制一个文本框,可以包
含文本 . 这个对象同样也有 setText 与 getText 方法,不过它还能编辑输入 .
49
处理文字输入
50
处理文字输入# convert_gui.pyw# 使用简单的图形界面# 实现的摄氏度转华氏度的程序 .
from graphics import *
def main(): win = GraphWin("Celsius Converter", 300, 200) win.setCoords(0.0, 0.0, 3.0, 4.0) # 绘制界面 Text(Point(1,3), " Celsius Temperature:").draw(win) Text(Point(1,1), "Fahrenheit Temperature:").draw(win) input = Entry(Point(2,3), 5) input.setText("0.0") input.draw(win) output = Text(Point(2,1),"") output.draw(win) button = Text(Point(1.5,2.0),"Convert It") button.draw(win) Rectangle(Point(1,1.5), Point(2,2.5)).draw(win)
51
处理文字输入 # 等待一次鼠标点击 win.getMouse()
# 转换输入 celsius = eval(input.getText()) fahrenheit = 9.0/5.0 * celsius + 32
# 展示输出并且改变按钮 output.setText("%0.1f" % fahrenheit) button.setText("Quit")
# 等待点击并推出 win.getMouse() win.close() main()
52
处理文字输入
53
处理文字输入• 运行时,这个程序会绘制一个带有输入框
的窗口,以供用户输入摄氏度,还带有一个按钮来进行转换 .– 这个按钮当前还没有用,只是个摆设!我们现
在只是等待任意一次鼠标点击 .
54
处理文字输入• 初始时 , 我们设置输入框包含内容 “ 0.0”.
• 用户可以删掉这个值然后另外输一个值 .
• 当用户点击鼠标时,程序就会停止结束——由于我们也不关心在哪儿点的鼠标,所以我们不会存储点的位置 !
55
处理文字输入• 对输入处理分为三个步骤 :
– 输入的值会被 eval函数转换成数字 .– 这个数字会被转为华氏温度 .–然后这个数字会被转成字符串然后转成要输出
的格式,在 output字符区域中输出 .