pythoncamp0

唯一作业:
  • 可回放的点彩画板
  • 期待:
    • 三种形状画笔可选: 三角/方形/圆形
    • 颜色可定义: 颜色名 或是 RGB 声明
    • 每次 鼠标 点击画板任意一处,都绘制一个当前画笔可用彩色形状
    • 可记录1024次点彩绘制行为
    • 可回放整个记录的绘制行为
  • 要求:
    • 基础: 有画笔,可点绘
    • 可用: 有画笔,有颜色,可点绘
    • 合格: 有画笔,有颜色,可点绘,可回放
    • 天才: 有画笔,有颜色,可点绘,可回放,回放速度可调节,回放可输出为文件
需要的编程知识:
  • 定义一个绘制处理函数,用来在画布上绘画/负责更新画布

def draw(canvas) :

  • 注册绘制处理函数,调用draw函数,每秒执行60次,就是说,刷新频率60Hz

frame.set_draw_handler(draw)

  • 画画布的背景

frame.set_canvas_background('White')

  • 标签

    文本内容,宽度

label = frame.add_label("text", 200)

  • 画圆 在draw函数下,用canvas.draw_circle画圆

    canvas.draw_circle(圆心坐标, 圆半径, 圆边缘线的宽度, 边缘线的颜色, 圆圈填充色)

  • 鼠标点绘 用鼠标和画布进行交互,在点击位置绘制一个图形

    需要做两件事:创建一个鼠标处理函数 , 注册这个处理函数

    创建鼠标点击事件的处理函数,形参pos是获取的鼠标点击画布的坐标,画布左上角是坐标原点(0,0),画布左边是Y轴正向,上边是X轴正向

    坐标是一个元组,这意味着pos的值是不能改变的,要通过<list_name> = list(pos)将元组的数据复制后放入一个列表

def click(pos):
       <list_name> = list(pos)
注册这个事件处理函数,激活鼠标点击,当有鼠标点击时,使用函数`click`处理

frame.set_mouseclick_handler(click)

  • 列表 可以将多个数据相互关联在一起,进行保持

    • 创建 列表的一个特征 必须有一个左括号和一个右括号,在括号里面 可以包含任意数量的元素 并以逗号分隔

      其中的元素可以是 Python允许的可为变量赋值的任意数据类型

      包括允许的对变量的任意赋值 所以列表元素可以是数字、字符串,可以是其他列表 或者其他类型

      1 = [1, 3, 4, -7]

      2 = ['milk', 'eggs', 'bread']

      3 = [['a', 'b', 'c'], [4, 7], []]

    • 访问 列表和字符串都是一种序列 所以很多对字符串的操作同样对列表也适用

      可以用len函数打印出列表长度 len(list_name)

      可以访问列表里面的单个元素,元素编号从“0”开始

      2 = 1[0]

      2 = 1[-1]

      可以对列表做分割,把它赋给一个新的列表。注意,这里表示从截取列表1中,从编号1到编号2的元素,不包括编号3

      2 = 1[1:3]

    • 更新 列表还可以改变列表中的元素

      我可以给元素 赋一个新的值,比如给列表12的第0个元素赋值'cheese'

      12[0] = 'cheese'

    • 增量更新 list_name.append(632)

      可以将632添加到列表的尾部,列表变大了 变长了

      可以在append中放置一个序列,想把它变多长就多长

    • 遍历整个列表 从编号0开始,一次一个 按顺序把列表里每一个元素读取出来,这叫做遍历

      在 Python 里 遍历由 for 循环完成,for 语句以冒号结束 代码块缩

      for <ball_pos> in <ball_list> :

      for ball_pos in ball_list 实际上是说,遍历 ball_list,并对于列表中的每一个元素,将 ball_pos 赋值为该元素

  • 计时器 创建一个计时器 一旦开始计时 计时器会在指定的时间间隔周期性调用给定的事件处理程序

需要两个参数:一个interval和一个计时器处理程序

第一个参数是 我们希望在两次调用之间插入多少毫秒的间隔

第二个参数也就是计时器调用的处理程序

<timer_name> = simplegui.create_timer(interval, review)

启动计时器

<timer_name>.start()

停止计时器

<timer_name>.stop()

  • 写程序的方式: 先写出一些简单的东西,稍微改变它一下,运行它,使它还能继续工作

稍微改变它一下,运行它,使它还能继续工作

稍微改变它一下,运行它,使它还能继续工作

最后会得到想要的结果,过程中不会犯太多的错误

如果你进行小的改动 你最终会得到一个更好的系统

设计步骤:

从最简单的开始

  1. 创建框,画布背景设置为白色set_canvas_background('White')
  2. 画笔形状,要求三种形状:三角/方形/圆形,在Canvas中只找到Draw Circle on Canvas,就先画园吧,用按钮进行设置
  3. 颜色,原本设想用下拉框选择,但没找到这种方式,所以依然用按钮的方式,定义几个函数赋值颜色的字符串,注册按钮并调用函数
  4. 点绘,注册鼠标点击事件set_mouseclick_handler(click),定义函数draw将坐标转换成列表,先画出圆形
  5. 颜色有了,得想办法画三角和方形,找了一下,在CanvasExamples:Drawing Shapes里面画了几种图形,有需要的三角和方形,

    依葫芦画瓢,用获取的鼠标点击坐标加减25像素,确定了几个顶点,然后是边框、填充色。

    方形遇到点问题,几个顶点的顺序不对,画得很诡异,仔细研究了一下,从左上角逆时针画了一圈,问题解决。

现在可以点绘,但历史信息没有被记录,接下来要用到列表保存每次点击的信息了

[代码:Drawing board V1.0]

  1. 列表,考虑到需要保存的信息,列表中要包含:鼠标点击的坐标、颜色、笔画形状,创建了一个列表Pol_list,元素用变量替代。

    在鼠标事件的处理函数下,每次的点击坐标追加到Pol_list进行保存,同时保存这次点击用到的颜色和形状

[代码:Drawing board V2.0]

  1. 回放,最困难的一步,最开始想到的是体育比赛中的录像回放。

    考虑在列表添加一个time做累加,然后用index找出位置

    list[0:1024]截取固定范围赋值给另一个列表名,然后用range(1024)for in之类的方法实现。

    但想到这里已经凌乱了,怎么用一个draw实现。

    后来想到,是不是想得太多了,或许可以理解为回退呢?先做手动回放功能

    然后考虑怎么用一个draw显示正常绘画和回退的图像,想到用全局变量be``end表示需要显示的列表范围,endclick中累加

    怎么在draw区分两个范围呢

    TrueFalse判断正常绘画还是回退

    回放按钮中定义全局变量review = True,当再次用鼠标绘画时,在click中重新赋值为False,从而显示当前的绘画进度

    同时,在回放函数中设置累加器n += 1,在draw切换到回放的代码时,每次点击一次回放,用全局end减去累加器,实现从当前版本回退

    这样,手动回退就完成了

[代码:Drawing board V3.0]

  1. 接下来是可变速回放,就需要改为自动回退了,引入计时器,在一定的时间间隔后,自动执行回退函数

    原本想在加速、减速函数中累加不同大小的时间延迟,但好像没有效果,只好定义了三个不同速度的定时器,用不同的开始、结束组合实现变速

  2. 最后,界面优化,变速时间延迟的调整

[代码:Drawing board V4.0]

最后

回放输出为文件,我理解是用字典保存回放时的元素信息,然后尝试打印了一下,结果不太对,还需要研究一下。

有点体会到了“衣带渐宽终不悔,为伊消得人憔悴”的感觉,折腾了一下午,吃晚饭还在想……