2022年 11月 9日

Python-七段数码管绘制问题分析

问题分析
七段数码管,值7段小的数码管构成的数字
选择不同数码管的量或者面,可以形成0-9 A-F不同的数字和字母的组合
在交通路口-红绿灯倒计时,家里的闹钟计数,有大量七段数码管的效果

需求分析
用程序绘制七段数码管
解决:使用turtle绘图体系绘制七段数码管
效果如图:
在这里插入图片描述
基本讲解;
基本思路
步骤1:绘制单个数字对应的数码管
步骤2:获得一串数字,绘制对应的数码管
步骤3:获得当前系统时间,绘制对应的数码管

步骤1:

首先,七段数码管有一定顺序
-七段数码管由7个七段数码管是由七个基本线条构成
-七段数码管可以由固定顺序
-不同数字显示不同的线条
我们对其逐一编号得到
在这里插入图片描述
如果从左边的位置逐一编号,形成行动序列,覆盖七段线条,不同的线条是否被绘制,便能形成不同的显示数字

下面通过函数对功能做一些分割
例:
由于绘制需要使用到海龟绘图库,所以:

import turtle    #引用海龟绘图库
  • 1

将绘制一条线的作用,定义为一个函数

def drawline(draw):
  • 1

由于画一条线有两种情况,一种为真实的画一条线,另一种为画笔移动到某个位置后落下
所以用变量draw来控制

	trutle.pendown() if draw else turtle.penup()    #如果draw变量为真值,那么画笔落下,如果不是,抬起海龟画笔
	turtle.fd(40)    #接下来海龟前进40个像素
	turtle.right(90)    #接下来海龟向右旋转90度
  • 1
  • 2
  • 3

下面为绘制7条线

def drawDigit(digit):    这定义一个函数,用来根据数字绘制七段数码管
    drawLine(true) if digit in [2,3,4,5,6,8,9] else drawLine(False)
    drawLine(true) if digit in [0,1,3,4,5,6,8,9] else drawLine(False)
    drawLine(true) if digit in [0,2,3,5,6,8,9] else drawLine(False)
    drawLine(true) if digit in [0,2,6,8] else drawLine(False)
  • 1
  • 2
  • 3
  • 4
  • 5

以上解释为,如果digit变量的参数在[]中,那么执行之前定义的drawLine()函数变量为真的结果
即海龟画笔落下,向前绘制40个像素,再海龟向右旋转90度
若digit变量的参数不在[]中,那么执行为假的结果,画笔抬起,移动但是不绘制直线
具体过程参考上面那张图的序号的顺序
因为根据上述函数,已经进过了4次判断,所以消耗了4条线的序号,如果继续执行以上函数,那么将会造成循环旋转
如图
在这里插入图片描述
因为此时函数体已经将海龟从序号4转向到序号1的前进方向,所以我们将海龟向左(也就是向上)旋转90度
以便海龟继续向序号5的方向前进

	turtle.left(90)
  • 1

之后继续进行判断

    drawLine(true) if digit in [0,4,5,6,8,9] else drawLine(False)
    drawLine(true) if digit in [0,2,3,5,6,7,8,9] else drawLine(False)
    turtle.left(180) #转回数字序号1的前进方向,也就是从右往左绘制的方向

  • 1
  • 2
  • 3
  • 4

继续三次右转,就可以完成这7条线的绘制
疑问1:为什么定义2个函数体
答:如果只使用drawLine,将会无限绘制序号1-4,因为他只有一个右转和前进参数,无法判断何时绘制
所以我们使用了第二个函数drawDigit用来根据输入的数字 控制drawLine函数的绘制

疑问2:如何根据数字绘制 或 为何使用if digit in []
答:按照图上起点和的序号来划分,序号代表7根线的行走顺序,也是函数体的判断执行顺序,函数体中判断的第一句
便是中间那条直线,数字1的绘制顺序,因为1和0还有7不需要这条线,所以
drawLine(true) if digit in [2,3,4,5,6,8,9] else drawLine(False)
只有当输入的参数为0 1 7数字以外的数字才可以进行绘制,否则画笔抬起

疑问3:最后为何要turtle.left(180)
答:因为要完成 步骤3:获得当前系统时间,绘制对应的数码管
所以要将海龟转向从左往右的方向,以便下一个绘制的数字不和之前绘制的数字重叠

所以接下来为了绘制后续数字,需要确定下一个数字绘制的位置
所以

	turtle.penup() #抬起画笔
	turtle.fd(20)    #画笔前进20个像素,为下一个数字做准备
  • 1
  • 2

接下来绘制后续数字,如图
在这里插入图片描述步骤2绘制多个数码管

我们需要给出一段字符串 绘制其他的七段数码管
因还需要执行步骤三,所以定义一个函数drawDate(date)
防止内容杂乱,所以抄一遍代码过来

import turtle
def drawLine(draw):    #用来绘制单端数码管的代码
	.......
def drawDigit(digit):    #根据数字绘制七段数码管的代码
	.......
def drawDate(date):	#获得要输入的数字
    for i in date:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
**↑逐一解析获得时间的字符串中的每一个字符,根据下面的步骤转换为数字后进行判断,如果无法理解建议看for in遍历循环的使用**
  • 1
	drawDigit(eval(i)) #通过eval()函数将数字变为整数
  • 1

接下来运行整个函数

def main():
    turtle.setup(800,350,200,200)    #定义当前画布大小
    turtle.penup()    #抬起画笔
    turtle.fd(-300)    #定义当前画笔的起始位置
    turtle.pensize(5)    #定义画笔的粗细
    drawDate('20181010')    #用drawDate函数赋予整个执行的参数,类似于一个日期
    turtle.hideturtle()
    turtle.done()   #函数完毕,并不关闭窗体
main()  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

↑调用主函数,启动程序运行,因为函数定义并不运行任何的代码,所以要调用主函数让整个程序运行起来

整体代码如图
在这里插入图片描述在这里插入图片描述步骤三 获得当前系统时间,绘制相应数码管
因每根数码管中间间隔不美观,所以优化之前的代码
定义一个drawGap函数,用来在每段数码管之间空出一个缺口
例如红圈中的缺口
在这里插入图片描述

def drawGap():
    turtle.penup()
    turtle.fd(5)

def drawLine(draw):
    drawGap()
    turtle.pendown() if draw else turtle.penup()
    turtle.fd(40)
    drawGap()
    turtle.right(90)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

将drawGap()函数插入在drawLine()函数的开始和结尾处,可将画笔开头和结尾分别用小的像素作为间隔
接下来获取系统时间
我们使用time库获得系统当前时间
在七段数码管中间,添加年月日标记
希望年月日的颜色不同

接下来扩展这些功能

import turtle,time    #调用海龟库与时间库
.....def drawDate(date):        #date为日期,格式为'%Y-%m=%d+'
    turtle.pencolor("red")    #将画笔改为红色
    for i in date:
        if i =='-':
            turtle.write('年',font=("Arial",18,"normal"))
            turtle.pencolor("green")
            turtle.fd(40)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

以下是turtle.write的参数说明,相应本来第二周就有,但是目前笔记还没有贴上

turtle.write(arg,move=false,align='left',font=('arial',8,'normal'))
  • 1
用途:在当前海龟位置写入文本
arg--信息,将写入Turtle绘画屏幕。

move(可选)--/假。

align(可选)--字符串“左(left)”、“中(center)”或“右(right)”之一。

font(可选)--三个字体(fontname字体名、fontsize字体大小、fonttype字体类型)。

写入文本 - arg的字符串表示形式 - 当前

根据“对齐”(“左”、“中”或“右”)定位乌龟以及给定的字体。

如果move为true,则笔将移动到右下角。

在默认情况下,move为false
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

以下懒得打代码,直接上图片,该解释都解释过了
在这里插入图片描述进一步为了获得系统时间
我们给drawDate(date)中的date变量赋予一个参数

	drawDate(time.strftime('%Y-%m=%d+',time.gmtime()))
	time.strftime()给时间进行格式化一个格式
	time.gmtime()获取当前系统时间
  • 1
  • 2
  • 3

结果如图
在这里插入图片描述疑问1:为什么要格式化字符
答:因为需要用这些字符去判断年月日

下面我也不放这些代码了,因为有点长,但是看了这么多解析,和以上代码,应该懂得了许多,自己抄抄改改就OK

总结:
-我们通过调用定义过的函数,实现了代码复用
-模块化思维:确定了模块接口,封装功能
-抽象过程为规则,计算机自动执行

写了这么多,其实数码管还有很多可以扩展的内容,可以等待探索
例如
-绘制带小数点的七段数码管
-带刷新的倒计时数码管效果
-绘制七段以上的高级数码管等