Python程序设计(第三版)课后题答案 第四章
编程练习题
- 1.修改程序,是它做到:
a.绘制正方形而不是圆形。
b.每次连续点击在屏幕上绘制一个额外的方块(而不是移动已有的方块)。
c.循环之后在窗口上打印消息“Click again to quit”,等待最后一次点击,然后关闭窗口。
答案:
程序思路:给出的程序已经能够绘制圆形,而且随着鼠标点击圆形会随之移动。先将图形窗口的单位由像素设置为较为方便的数值,更改程序使用矩形函数绘制一个长度为10(数值可以自由设置)的正方形;在for循环内依次获得鼠标点击位置的坐标,然后计算图形的对角点的坐标,并绘制和修饰图形。结束循环后生成文本显示信息,再次获取点击后退出程序。
from graphics import *
def main(): # 循环点击绘制方块
win = GraphWin("Rectangle", 600, 600)
win.setCoords(0.0, 0.0, 100.0, 100.0) # 将图像坐标统一为宽窄为100的方块
shape = Rectangle(Point(50, 50), Point(60, 60)) # 绘制方块的边长为10
shape.setOutline("red")
shape.setFill("red")
shape.draw(win)
for i in range(10):
p = win.getMouse()
x1 = p.getX() - 5 # 计算新的位置的方块的对角坐标
x2 = p.getX() + 5
y1 = p.getY() - 5
y2 = p.getY() + 5
shape = Rectangle(Point(x1, y1), Point(x2, y2))
shape.setOutline("red")
shape.setFill("red")
shape.draw(win)
t = Text(Point(50, 80), "Click again to quit!")
t.setSize(20)
t.setFace("courier")
t.setStyle("bold")
t.setTextColor("black")
t.draw(win)
win.getMouse()
main()
输出:
- 2.箭靶的中心圆为黄色,围绕着红色、蓝色、黑色和白色的同心环。每个环具有相同的宽度,与黄色圆的半径相同。编写一个绘制这种箭靶的程序。(提示:稍后绘制的对象将出现在先前绘制的对象的上面。)
答案:
程序思路:程序思路较为简单,使用圆形函数生成圆心相同,半径依次递增的函数。需要注意的是要先打印最大的底层圆,否则会被后面的圆覆盖。
def main(): # 绘制同心环箭靶
win = GraphWin("箭靶", 600, 600)
win.setCoords(0.0, 0.0, 100.0, 100.0) # 将图像坐标统一为宽窄为100的方块
shape = Circle(Point(50, 50), 25) # 绘制最外侧圆
shape.setOutline("white")
shape.setFill("white")
shape.draw(win)
shape = Circle(Point(50, 50), 20) # 绘制第四层圆
shape.setOutline("black")
shape.setFill("black")
shape.draw(win)
shape = Circle(Point(50, 50), 15) # 绘制第三层圆
shape.setOutline("blue")
shape.setFill("blue")
shape.draw(win)
shape = Circle(Point(50, 50), 10) # 绘制第二层圆
shape.setOutline("red")
shape.setFill("red")
shape.draw(win)
shape = Circle(Point(50, 50), 5) # 绘制最中心圆
shape.setOutline("yellow")
shape.setFill("yellow")
shape.draw(win)
win.getMouse()
main()
输出:
- 3.编写一个绘制某种面孔的程序。
答案:
程序思路:这个程序的难易程度取决于你设计的面孔的复杂程度。这里仅展示最简单的情况,利用圆形、矩形配合不同的填充颜色生成简单的面孔。注意要计算好每个图形的点的坐标。
def main(): # 绘制简单面孔
win = GraphWin("面孔", 600, 600)
win.setCoords(0.0, 0.0, 100.0, 100.0) # 将图像坐标统一为宽窄为100的方块
win.setBackground("white")
# 绘制脸
face = Circle(Point(50, 50), 25)
face.setFill("peachpuff")
face.draw(win)
# 绘制左眼
eye_left = Circle(Point(40, 55), 3)
eye_left.setFill("white")
eye_left.draw(win)
# 绘制右眼
eye_right = Circle(Point(60, 55), 3)
eye_right.setFill("white")
eye_right.draw(win)
# 绘制鼻子
nose = Rectangle(Point(48, 42), Point(52, 45))
nose.setFill("black")
nose.draw(win)
# 绘制嘴巴
mouth = Rectangle(Point(47, 32), Point(53, 34))
mouth.setFill("red")
mouth.draw(win)
win.getMouse()
win.close()
main()
输出:
- 4.编写一个用圣诞树和雪人绘制冬季场景的程序。
答案:
程序思路:这个程序主要有两个元素,分别编写两个函数来生成雪人和圣诞树。雪人snowman函数,主要利用圆形表示头部、身体、眼睛等部位,用矩形表示鼻子,嘴巴等位置,填充适当色彩。圣诞树christmas_tree函数主要是利用循环生成大小递减的三角形表示树的树冠,三角形主要利用Polygon函数实现,再绘制一个短的矩形表示树的树干,顶部再加一个五角星用以装饰。再对窗口整体加以修饰,填充一个你喜欢的颜色。
def snowman(win, x, y):
# 绘制头部
head = Circle(Point(x, y), 7)
head.setFill("white")
head.draw(win)
# 绘制身体
body = Oval(Point(x - 15, y - 38), Point(x + 15, y - 7))
body.setFill("white")
body.draw(win)
sign1 = Circle(Point(x, y - 9), 0.8)
sign1.setFill("red")
sign1.draw(win)
sign2 = Circle(Point(x, y - 11), 0.8)
sign2.setFill("green")
sign2.draw(win)
sign3 = Circle(Point(x, y - 13), 0.8)
sign3.setFill("yellow")
sign3.draw(win)
# 绘制左眼
eye_left = Circle(Point(x - 3, y + 2), 1)
eye_left.setFill("white")
eye_left.draw(win)
eye_leftq = Circle(Point(x - 3, y + 2), 0.1)
eye_leftq.setFill("black")
eye_leftq.draw(win)
# 绘制右眼
eye_right = Circle(Point(x + 3, y + 2), 1)
eye_right.setFill("white")
eye_right.draw(win)
eye_rightq = Circle(Point(x + 3, y + 2), 0.1)
eye_rightq.setFill("black")
eye_rightq.draw(win)
# 绘制鼻子
nose = Rectangle(Point(x - 0.5, y - 0.8), Point(x + 0.5, y + 0.2))
nose.setFill("black")
nose.draw(win)
# 绘制嘴巴
mouth = Rectangle(Point(x - 1.5, y - 4), Point(x + 1.5, y - 2))
mouth.setFill(color_rgb(255, 100, 100))
mouth.draw(win)
# 添加祝福文本
t = Text(Point(x+2, y - 25), "圣诞节快乐!")
t.setFill(color_rgb(200, 100, 150))
t.setSize(15)
t.setStyle("bold")
t.draw(win)
def christmas_tree(win, x, y, height):
# 绘制树干
trunk = Rectangle(Point(x - 1.5, y), Point(x + 1.5, y + 15))
trunk.setFill("brown")
trunk.draw(win)
# 绘制树冠的每一层
bottom = Point(x, y + 15)
for i in range(height // 10, 0, -1): # 根据输入的不同高度设计圣诞树的层数,模10取整
top_left = Point(x - i**1.5, bottom.getY()) # 让前一个三角形的顶点高度作为下一个三角形的底的高度,三角形的底边宽度递减
top_right = Point(x + i**1.5, bottom.getY())
bottom = Point(x, y + height - i**1.9) # 计算三角形顶点的坐标
layer = Polygon(top_left, top_right, bottom)
layer.setFill("green")
layer.draw(win)
print(bottom.getX(), bottom.getY())
# 添加星星到树顶
star = Polygon(Point(57, 79), Point(63, 79), Point(58, 76), Point(60, 81), Point(62, 76))
star.setFill("yellow")
star.setOutline("yellow")
star.draw(win)
# 创建窗口
win = GraphWin("Snowman and Christmas_Tree", 600, 600)
win.setCoords(0, 0, 100, 100)
win.setBackground("pink")
# 绘制雪人和圣诞树
snowman(win, 28, 65)
christmas_tree(win, 60, 10, 70)
# 等待用户关闭窗口
win.getMouse()
win.close()
输出:
- 5.编写一个程序,在屏幕上绘制5个骰子,是一把顺子(1,2,3,4,5,或2,3,4,5,6)。
答案:
程序思路:编写两个小的函数,一个用来生成骰子的框,一个用来生成点,函数主要简化了填充和绘制的步骤。根据窗口大小,设计骰子的摆放位置,计算中心点坐标,调用五次函数绘制骰子框。再根据骰子显示的点数的不同,计算好每个点的中心位置,调用点函数,调整点的半径大小,在骰子内生成点即可。
def draw_touzi(win, x1, y1, x2, y2):
t = Rectangle(Point(x1, y1), Point(x2, y2))
t.setOutline("black")
t.setFill("white")
t.draw(win)
def draw_point(win, x, y, r):
p = Circle(Point(x, y), r)
p.setFill("red")
p.draw(win)
def touzi():
win = GraphWin("touzi", 600, 600)
win.setCoords(0, 0, 100, 100)
win.setBackground("green")
draw_touzi(win, 5, 45, 15, 55)
draw_point(win, 10, 50, 2)
draw_touzi(win, 25, 45, 35, 55)
draw_point(win, 30, 47.5, 1.5)
draw_point(win, 30, 52.5, 1.5)
draw_touzi(win, 45, 45, 55, 55)
draw_point(win, 50, 46.8, 1.1)
draw_point(win, 50, 49.8, 1.1)
draw_point(win, 50, 52.8, 1.1)
draw_touzi(win, 65, 45, 75, 55)
draw_point(win, 67.5, 47.5, 1.1)
draw_point(win, 67.5, 52.5, 1.1)
draw_point(win, 72.5, 47.5, 1.1)
draw_point(win, 72.5, 52.5, 1.1)
draw_touzi(win, 85, 45, 95, 55)
draw_point(win, 90, 50, 1.1)
draw_point(win, 87.5, 47.5, 1.1)
draw_point(win, 87.5, 52.5, 1.1)
draw_point(win, 92.5, 47.5, 1.1)
draw_point(win, 92.5, 52.5, 1.1)
win.getMouse()
win.close()
touzi()
输出:
- 6.修改图形终值程序,让输入(本金和APR)也用Entry对象以图形方式完成。
答案:
程序思路:主要使用Entry文本框来进行参数输入,需要注意对文本框进行赋值和绘制,然后合理设置getMouse暂停,在确保输入了数据之后再进行转换和运算。
图形终值程序如下:
from graphics import *
def main():
# Introduction
print("This program plots the growth of a 10-year investment.")
# Get principal and interest rate
principal = float(input("Enter the initial principal: "))
apr = float(input("Enter the annualized interest rate: "))
# Create a graphics window with labels on left edge
win = GraphWin("Investment Growth Chart", 320, 240)
win.setBackground("white")
win.setCoords(-1.75, -200, 11.5, 10400)
Text(Point(-1, 0), ' 0.0K').draw(win)
Text(Point(-1, 2500), ' 2.5K').draw(win)
Text(Point(-1, 5000), ' 5.0K').draw(win)
Text(Point(-1, 7500), ' 7.5k').draw(win)
Text(Point(-1, 10000), '10.0K').draw(win)
# Draw bar for initial principal
bar = Rectangle(Point(0, 0), Point(1, principal))
bar.setFill("green")
bar.setWidth(2)
bar.draw(win)
# Draw a bar for each subsequent year
for year in range(1, 11):
principal = principal * (1 + apr)
bar = Rectangle(Point(year, 0), Point(year + 1, principal))
bar.setFill("green")
bar.setWidth(2)
bar.draw(win)
input("Press <Enter> to quit.")
win.close()
main()
修改后程序如下:(修改语句用长#号标注)
from graphics import *
def main():
# Create a graphics window with labels on left edge
win = GraphWin("Investment Growth Chart", 320, 240)
win.setBackground("white")
win.setCoords(-1.75, -200, 11.5, 10400)
p = Entry(Point(3, 10000), 6) ###########设置Entry输入框,并赋值为0,绘制在图中
p.setText("0") ###########
p.draw(win) ###########
a = Entry(Point(6, 10000), 4) ###########
a.setText("0.0") ###########
a.draw(win) ###########
Text(Point(-1, 0), ' 0.0K').draw(win)
Text(Point(-1, 2500), ' 2.5K').draw(win)
Text(Point(-1, 5000), ' 5.0K').draw(win)
Text(Point(-1, 7500), ' 7.5k').draw(win)
Text(Point(-1, 10000), '10.0K').draw(win)
win.getMouse() ########### 设置一次鼠标点击,让用户有时间更改Entry文本框中的值
principal = int(p.getText()) ########### 点击后将输入的值转换为float类型,进行运算绘图
apr = float(a.getText()) ###########
# Draw bar for initial principal
bar = Rectangle(Point(0, 0), Point(1, principal))
bar.setFill("green")
bar.setWidth(2)
bar.draw(win)
# Draw a bar for each subsequent year
for year in range(1, 11):
principal = principal * (1 + apr)
bar = Rectangle(Point(year, 0), Point(year+1, principal))
bar.setFill("green")
bar.setWidth(2)
bar.draw(win)
win.getMouse() ########### 设置点击窗口后关闭窗口
win.close() ###########
main()
输出:
- 7.圆的交点。
编写一个计算圆与水平线的交点的程序,并以文本和图形方式显示信息。
输入:圆的半径和线的截距。
输出:在坐标为从(-10,-10)到(10,10)的窗口中,以(0,0)为中心,以给定半径绘制的圆。
用给定的Y轴截取一根水平线穿过窗口。
用红色绘制两个交点。
打印出交叉点的X值。
公式: x = ± r 2 − y 2 x=±\sqrt{r^2 - y^2 } x=±r2−y2
答案:
程序思路:利用程序输入直接绘制圆和直线,并计算交点,然后用红色的小圆代替点标注出来,根据公式计算X的正负值,打印输出即可。
def cricle_intersection(r, y): # 函数的输出是圆的半径和截距
win = GraphWin("Cricles_intersection", 600, 600)
win.setCoords(-10, -10, 10, 10)
win.setBackground("white")
cricle = Circle(Point(0, 0), r)
cricle.setOutline("black")
cricle.draw(win)
line = Line(Point(-10, y), Point(10, y))
line.setOutline("black")
line.draw(win)
x1 = sqrt(r**2-y**2) # 调用开平方函数计算x的正负值
x2 = -x1
p1 = Circle(Point(x1, y), 0.2)
p1.setFill("red")
p1.draw(win)
pt1 = Text(Point(x1 + 1, y - 1), "x1")
pt1.draw(win)
p2 = Circle(Point(x2, y), 0.2)
p2.setFill("red")
p2.draw(win)
pt2 = Text(Point(x2 - 1, y - 1), "x2")
pt2.draw(win)
print("x1 =", x1, " x2 =", x2)
win.getMouse()
win.close()
cricle_intersection(5, -4)
输出:
- 8.线段信息。
该程序允许用户绘制线段,然后显示关于线段的一些图形和文本信息。
输入:两次鼠标点击线段的终点。
输出:以青色绘制线段的中点。
绘制线段。
打印线的长度和斜率。
公式:
l e n g t h = d x 2 + d y 2 length = \sqrt{dx^2 + dy^2 } length=dx2+dy2
答案:
程序思路: 利用getMouse函数获点的位置,分别取出坐标绘制线段,再计算得到线段的中点,绘制在窗口中。利用坐标和公式计算线段的斜率和长度,打印输出。
def line_segment():
win = GraphWin("line_segment", 600, 600)
win.setCoords(0, 0, 100, 100)
win.setBackground("white")
p1 = win.getMouse() # 通过点击获取点
p1.draw(win)
p2 = win.getMouse()
p2.draw(win)
x1 = p1.getX() # 取出两点的坐标
y1 = p1.getY()
x2 = p2.getX()
y2 = p2.getY()
dx = x2 - x1
dy = y2 - y1
line = Line(Point(x1, y1), Point(x2, y2)) # 根据两点坐标绘制直线
line.draw(win)
c = Circle(Point((x1 + x2) / 2, (y1 + y2) / 2), 0.8) # 绘制直线中点,用一个小圆代替,填充青色
c.setFill("cyan")
c.draw(win)
slope = dy / dx # 计算斜率
length = sqrt(dx ** 2 + dy ** 2) # 计算线段长度
s = round(slope, 3) # 分别保留三位小数
lth = round(length, 3)
print("slope=", s, " length=", lth)
win.getMouse()
win.close()
line_segment()
输出:
- 9.矩形信息。
此程序显示有关用户绘制的矩形信息。
输入:两次鼠标点击作为矩形的对角。
输出:绘制矩形。
打印矩形的周长和面积。
公式:面积=(长度)(宽度) ;周长=2(长度+宽度)
答案:
程序思路: 利用鼠标点击获取两个点,作为矩形对角点,分别取出坐标,同时可以得到矩形另外两点的坐标,利用Polygon函数依次连接四点即可绘制矩形;通过对角坐标点可以计算横纵坐标各自的差值,作为矩形的长和宽,即可算得周长和面积,打印输出。
def draw_rectangle():
win = GraphWin("draw_rectangle", 600, 600)
win.setCoords(0, 0, 100, 100)
win.setBackground("white")
p1 = win.getMouse() # 通过点击获取点
p1.draw(win)
p2 = win.getMouse()
p2.draw(win)
x1 = p1.getX() # 取出两点的坐标
y1 = p1.getY()
x2 = p2.getX()
y2 = p2.getY()
x3 = x1
y3 = y2
x4 = x2
y4 = y1
dx = abs(x2 - x1) # 差值取为绝对值
dy = abs(y2 - y1)
rectangle = Polygon(Point(x1, y1), Point(x3, y3), Point(x2, y2), Point(x4, y4))
rectangle.setFill("pink")
rectangle.draw(win)
primeter = dy*2 + dx*2 # 计算周长
area = dx*dy # 计算面积
p = round(primeter, 3) # 分别保留三位小数
a = round(area, 3)
print("周长=", p, " 面积=", a)
win.getMouse()
win.close()
draw_rectangle()
输出:
- 10.三角形信息。
与上一个问题相同,但三角形的顶点有三次点击。
公式:关于周长,可参阅线段问题中的长度。
面积 = s ( s − a ) ( s − b ) ( s − c ) 面积 = \sqrt{s(s-a)(s-b)(s-c) } 面积=s(s−a)(s−b)(s−c)其中a,b,c是边长,s = (a + b + c)/2
答案:
程序思路: 与上一题类似,利用鼠标点击获取三个点,分别取出坐标,通过两点坐标分别求出三条边的长度,利用Polygon函数依次连接三点即可绘制三角形。
def draw_triangle():
win = GraphWin("draw_triangle", 600, 600)
win.setCoords(0, 0, 100, 100)
win.setBackground("white")
p1 = win.getMouse() # 通过点击获取点
p1.draw(win)
p2 = win.getMouse()
p2.draw(win)
p3 = win.getMouse()
x1 = p1.getX() # 取出三点的坐标
y1 = p1.getY()
x2 = p2.getX()
y2 = p2.getY()
x3 = p3.getX()
y3 = p3.getY()
dx1 = abs(x2 - x1)
dy1 = abs(y2 - y1)
a = sqrt(dx1 ** 2 + dy1 ** 2) # 计算第一边长度
dx2 = abs(x2 - x3)
dy2 = abs(y2 - y3)
b = sqrt(dx2 ** 2 + dy2 ** 2) # 计算第二边长度
dx3 = abs(x3 - x1)
dy3 = abs(y3 - y1)
c = sqrt(dx3 ** 2 + dy3 ** 2) # 计算第三边长度
triangle = Polygon(Point(x1, y1), Point(x2, y2), Point(x3, y3)) # 画出三角形
triangle.setFill("pink")
triangle.draw(win)
s = (a + b + c) / 2 # 计算s值,便于计算面积
area = sqrt(s * (s - a) * (s - b) * (s - c))
s = round(a + b + c, 3) # 分别保留三位小数
a = round(area, 3)
print("周长=", s, " 面积=", a)
win.getMouse()
win.close()
draw_triangle()
输出:
- 11.通过5次点击的房子。
编写一个程序,允许用户通过五次点击鼠标,绘制一个简答的房子。
前两次点击是房子的矩形框架的对角。
第三次点击指出矩形门的顶部边缘的中心。门的宽度应为房屋框架宽度的1/5。门的边框应从顶部的转角延伸到框架的底部。
第四次点击指出正方形窗口的中心。窗口的宽度是门的一半。
最后一次点击指出屋顶的顶点。屋顶的边缘将从顶点延伸到房屋框架的顶部边缘的转角。
答案:
程序思路: 按照题目要求分五次点击,每次点击完成不同的工作,注意门和窗户的宽度的计算,多次使用矩形函数,计算好对角点的坐标,按步骤进行即可。
def draw_home():
win = GraphWin("draw_home", 600, 600)
win.setCoords(0, 0, 100, 100)
win.setBackground("white")
p1 = win.getMouse() # 第一次点击取点
p1.draw(win)
p2 = win.getMouse() # 第二次点击取点
p2.draw(win)
x1 = p1.getX()
y1 = p1.getY()
x2 = p2.getX()
y2 = p2.getY()
home_box = Rectangle(Point(x1, y1), Point(x2, y2)) # 利用两点绘制矩形
home_box.draw(win)
p3 = win.getMouse() # 第三次点击取点
p3.draw(win)
x3 = p3.getX()
y3 = p3.getY()
dx1 = abs(x2 - x1)
door_width = dx1 / 5 # 门的宽度为房屋宽度的1/5
door = Rectangle(Point(x3 - door_width / 2, y1), Point(x3 + door_width / 2, y3)) # 矩形函数绘制门
door.draw(win)
p4 = win.getMouse() # 第四次点击取点
x4 = p4.getX()
y4 = p4.getY()
windows_width = door_width / 2 # 窗的宽度为门宽度的1/2
windows = Rectangle(Point(x4 - windows_width / 2, y4 - windows_width / 2), # 矩形函数绘制窗
Point(x4 + windows_width / 2, y4 + windows_width / 2))
windows.draw(win)
p5 = win.getMouse() # 第五次点击取点
x5 = p5.getX()
y5 = p5.getY()
x11 = x1 # 计算房屋的另一个顶点的坐标
y11 = y2
line1 = Line(Point(x5, y5), Point(x11, y11)) # 从屋顶顶点向房屋框架的两个顶点连线
line1.draw(win)
line2 = Line(Point(x5, y5), Point(x2, y2))
line2.draw(win)
win.getMouse()
win.close()
draw_home()
输出:
(如有错误,请读者留言指正!)