本篇文章通过使用简单的ascii字符在终端上画模拟时钟表盘,可以展示当前时间、天数、周数。
这里不使用第三方库。完整代码如下,你可以使用云社区自带的python运行组件,跑去来看看效果。
这里看到了是15日,也是一个周五。显示了当前时间11点51分27秒。
完整代码如下,或者可以在这里下到lumanyu/ascii_clock: Python script that prints out a clock in ASCII art style to the console (github.com)
#-*- coding: utf-8 -*-
#-----------------------------------------------------------------------
#
#-----------------------------------------------------------------------
class AsciiCanvas(object):
"""
ASCII canvas for drawing in console using ASCII chars
"""
def __init__(self, cols, lines, fill_char=' '):
"""
Initialize ASCII canvas
初始化画板,填充fill_char
"""
if cols < 1 or cols > 1000 or lines < 1 or lines > 1000:
raise Exception('Canvas cols/lines must be in range [1..1000]')
self.cols = cols
self.lines = lines
if not fill_char:
fill_char = ' '
elif len(fill_char) > 1:
fill_char = fill_char[0]
self.fill_char = fill_char
self.canvas = [[fill_char] * (cols) for _ in range(lines)] # 得到一个cols列的一维数组,然后lines个数组组成二维数组
def clear(self):
"""
Fill canvas with empty chars
"""
self.canvas = [[self.fill_char] * (self.cols) for _ in range(self.lines)] # 清空,用fill_char清空
def print_out(self):
"""
Print out canvas to console
"""
print(self.get_canvas_as_str()) # 打印到荧幕
def add_line(self, x0, y0, x1, y1, fill_char='o'):
"""
Add ASCII line (x0, y0 -> x1, y1) to the canvas, fill line with `fill_char`
用fill_char画线
"""
if not fill_char:
fill_char = 'o'
elif len(fill_char) > 1:
fill_char = fill_char[0]
if x0 > x1: # 从左边画到右边
# swap A and B
x1, x0 = x0, x1
y1, y0 = y0, y1
# get delta x, y
dx = x1 - x0
dy = y1 - y0
# if a length of line is zero just add point
if dx == 0 and dy == 0:
if self.check_coord_in_range(x0, y0): # 这个点在画布内
self.canvas[y0][x0] = fill_char
return
# when dx >= dy use fill by x-axis, and use fill by y-axis otherwise
# 哪条边长度长,就填哪边
if abs(dx) >= abs(dy):
for x in range(x0, x1 + 1): # 闭区间[x0,x1+1)
# 如果是竖线,y就是y0,如果是一条斜线,y的坐标按照比例重新计算绘图点y坐标
y = y0 if dx == 0 else y0 + int(round((x - x0) * dy / float((dx)))) #
if self.check_coord_in_range(x, y):
self.canvas[y][x] = fill_char # 填充点
else:
if y0 < y1: # 从下往上画
for y in range(y0, y1 + 1):
x = x0 if dy == 0 else x0 + int(round((y - y0) * dx / float((dy))))
if self.check_coord_in_range(x, y):
self.canvas[y][x] = fill_char
else: # 从上往下画
for y in range(y1, y0 + 1):
x = x0 if dy == 0 else x1 + int(round((y - y1) * dx / float((dy))))
if self.check_coord_in_range(x, y):
self.canvas[y][x] = fill_char
def add_text(self, x, y, text):
"""
Add text to canvas at position (x, y)
在指定位置添加文本
"""
for i, c in enumerate(text): # i为字的个数
if self.check_coord_in_range(x + i, y):
self.canvas[y][x + i] = c # 在[x,x+i]位置添加char
def add_rect(self, x, y, w, h, fill_char=' ', outline_char='o'):
"""
Add rectangle filled with `fill_char` and outline with `outline_char`
在画板外围添加方框,增加画面感
"""
if not fill_char:
fill_char = ' '
elif len(fill_char) > 1:
fill_char = fill_char[0]
if not outline_char:
outline_char = 'o'
elif len(outline_char) > 1:
outline_char = outline_char[0]
for px in range(x, x + w):
for py in range(y, y + h):
if self.check_coord_in_range(px, py):
if px == x or px == x + w - 1 or py == y or py == y + h - 1: #如果坐标位于画板四周
self.canvas[py][px] = outline_char
else:
self.canvas[py][px] = fill_char
def add_nine_patch_rect(self, x, y, w, h, outline_3x3_chars=None): #画方框格
"""
Add nine-patch rectangle
"""
default_outline_3x3_chars = (
'.', '-', '.',
'|', ' ', '|',
'`', '-', "'"
)
if not outline_3x3_chars:
outline_3x3_chars = default_outline_3x3_chars
# filter chars
filtered_outline_3x3_chars = []
for index, char in enumerate(outline_3x3_chars[0:9]):
if not char:
char = default_outline_3x3_chars[index]
elif len(char) > 1:
char = char[0]
filtered_outline_3x3_chars.append(char)
for px in range(x, x + w): #在方格绘图区域
for py in range(y, y + h): #在方格绘图区域
if self.check_coord_in_range(px, py): #在绘图区域把9个元素放上去
if px == x and py == y:
self.canvas[py][px] = filtered_outline_3x3_chars[0]
elif px == x and y < py < y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[3]
elif px == x and py == y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[6]
elif x < px < x + w - 1 and py == y:
self.canvas[py][px] = filtered_outline_3x3_chars[1]
elif x < px < x + w - 1 and py == y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[7]
elif px == x + w - 1 and py == y:
self.canvas[py][px] = filtered_outline_3x3_chars[2]
elif px == x + w - 1 and y < py < y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[5]
elif px == x + w - 1 and py == y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[8]
else:
self.canvas[py][px] = filtered_outline_3x3_chars[4]
def check_coord_in_range(self, x, y):
"""
检查坐标位于画布有效范围
Check that coordinate (x, y) is in range, to prevent out of range error
"""
return 0 <= x < self.cols and 0 <= y < self.lines
def get_canvas_as_str(self):
"""
Return canvas as a string
画布输出成可打印字符串,打印到荧幕
"""
return '\n'.join([''.join(col) for col in self.canvas])
def __str__(self):
"""
Return canvas as a string
"""
return self.get_canvas_as_str()
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#-----------------------------------------------------------------------
#
#-----------------------------------------------------------------------
import os
import time
import math
import datetime
x_scale_ratio = 1.75 #x轴调整系数,以y为基础长度,x=y乘以这个系数
def draw_second_hand(ascii_canvas, seconds, length, fill_char):
"""
Draw second hand
画秒针
"""
x0 = int(math.ceil(ascii_canvas.cols / 2.0))
y0 = int(math.ceil(ascii_canvas.lines / 2.0))
x1 = x0 + int(math.cos((seconds + 45) * 6 * math.pi / 180) * length * x_scale_ratio)
y1 = y0 + int(math.sin((seconds + 45) * 6 * math.pi / 180) * length)
ascii_canvas.add_line(int(x0), int(y0), int(x1), int(y1), fill_char=fill_char)
def draw_minute_hand(ascii_canvas, minutes, length, fill_char):
"""
Draw minute hand
画分针
"""
x0 = int(math.ceil(ascii_canvas.cols / 2.0))
y0 = int(math.ceil(ascii_canvas.lines / 2.0))
x1 = x0 + int(math.cos((minutes + 45) * 6 * math.pi / 180) * length * x_scale_ratio)
y1 = y0 + int(math.sin((minutes + 45) * 6 * math.pi / 180) * length)
ascii_canvas.add_line(int(x0), int(y0), int(x1), int(y1), fill_char=fill_char)
def draw_hour_hand(ascii_canvas, hours, minutes, length, fill_char):
"""
Draw hour hand
画小时针
"""
x0 = int(math.ceil(ascii_canvas.cols / 2.0))
y0 = int(math.ceil(ascii_canvas.lines / 2.0))
total_hours = hours + minutes / 60.0
x1 = x0 + int(math.cos((total_hours + 45) * 30 * math.pi / 180) * length * x_scale_ratio)
y1 = y0 + int(math.sin((total_hours + 45) * 30 * math.pi / 180) * length)
ascii_canvas.add_line(int(x0), int(y0), int(x1), int(y1), fill_char=fill_char)
def draw_clock_face(ascii_canvas, radius, mark_char):
"""
Draw clock face with hour and minute marks
画表盘,表盘上添加小时和分钟 数字形式
"""
x0 = ascii_canvas.cols // 2 #带四舍五入的除法,比如说10//3在python3中等于3,相当于int
y0 = ascii_canvas.lines // 2
# draw marks first
for mark in range(1, 12 * 5 + 1): #总共有60分钟,就是外面60个、刻度
x1 = x0 + int(math.cos((mark + 45) * 6 * math.pi / 180) * radius * x_scale_ratio)
y1 = y0 + int(math.sin((mark + 45) * 6 * math.pi / 180) * radius)
if mark % 5 != 0: #画刻度、
ascii_canvas.add_text(x1, y1, mark_char)
# start from 1 because at 0 index - 12 hour
for mark in range(1, 12 + 1): # 画小时数,圆周围的12个小时数
x1 = x0 + int(math.cos((mark + 45) * 30 * math.pi / 180) * radius * x_scale_ratio)
y1 = y0 + int(math.sin((mark + 45) * 30 * math.pi / 180) * radius)
ascii_canvas.add_text(x1, y1, '%s' % mark) #画小时数
def draw_clock(cols, lines):
"""
Draw clock
"""
if cols < 25 or lines < 25:
print('Too little columns/lines for print out the clock!')
exit()
# prepare chars
single_line_border_chars = ('.', '-', '.', '|', ' ', '|', '`', '-', "'")
second_hand_char = '.' #秒针像素点
minute_hand_char = 'o' #分针像素点
hour_hand_char = 'O' #小时针像素点
mark_char = '`'
if os.name == 'nt':
single_line_border_chars = ('.', '-', '.', '|', ' ', '|', '`', '-', "'") # ('\xDA', '\xC4', '\xBF', '\xB3', '\x20', '\xB3', '\xC0', '\xC4', '\xD9')
second_hand_char = '.' # '\xFA'
minute_hand_char = 'o' # '\xF9'
hour_hand_char = 'O' # 'o'
mark_char = '`' # '\xF9'
# create ascii canvas for clock and eval vars
ascii_canvas = AsciiCanvas(cols, lines) #创建大表盘
center_x = int(math.ceil(cols / 2.0))
center_y = int(math.ceil(lines / 2.0))
radius = center_y - 5 #表盘半径
second_hand_length = int(radius / 1.17) #秒针长度
minute_hand_length = int(radius / 1.25) #分针长度
hour_hand_length = int(radius / 1.95) #小时针长度
# add clock region and clock face
ascii_canvas.add_rect(5, 3, int(math.floor(cols / 2.0)) * 2 - 9, int(math.floor(lines / 2.0)) * 2 - 5) #添加外围方框
draw_clock_face(ascii_canvas, radius, mark_char) #画表盘
now = datetime.datetime.now()
# add regions with weekday and day if possible
if center_x > 25: #如果有绘图空间,添加周数和天数
left_pos = int(radius * x_scale_ratio) / 2 - 4
ascii_canvas.add_nine_patch_rect(int(center_x + left_pos), int(center_y - 1), 5, 3, single_line_border_chars) #添加小方框
ascii_canvas.add_text(int(center_x + left_pos + 1), int(center_y), now.strftime('%a')) #添加周数
ascii_canvas.add_nine_patch_rect(int(center_x + left_pos + 5), int(center_y - 1), 4, 3, single_line_border_chars)
ascii_canvas.add_text(int(center_x + left_pos + 1 + 5), int(center_y), now.strftime('%d')) #添加天数
# add clock hands
draw_second_hand(ascii_canvas, now.second, second_hand_length, fill_char=second_hand_char) #添加秒针
draw_minute_hand(ascii_canvas, now.minute, minute_hand_length, fill_char=minute_hand_char) #添加分针
draw_hour_hand(ascii_canvas, now.hour, now.minute, hour_hand_length, fill_char=hour_hand_char) #添加小时针
# print out canvas
ascii_canvas.print_out() #打印到荧幕
def main():
lines = 30
cols = int(lines * x_scale_ratio)
# set console window size and screen buffer size
if os.name == 'nt':
os.system('mode con: cols=%s lines=%s' % (cols + 1, lines + 1))
while True:
os.system('cls' if os.name == 'nt' else 'clear') #清屏
draw_clock(cols, lines) #画时钟
time.sleep(0.2) #每0.2秒进行刷新,如果觉得屏幕太闪,把这个数调大点
if __name__ == '__main__':
main()
这份代码里,我们声明了一个class AsciiCanvas
类来模拟画布,并提供了以下方法
于是我们的主体程序里就可以这样做
这里推荐腾讯云的海外主机,因为对于开发人员,有时候需要GitHub能够快速稳定的连接。所以我的开发机都会去买腾讯云香港或者新加坡地区机器,而且现在有活动2024新春采购节也很优惠。
比如这个新加坡地区的活动,我们个人用开发机选择最便宜配置基础上再打2折。按照小时数收费,用多久收费多久。
云服务器CVM购买_云服务器CVM选购 - 腾讯云 (tencent.com)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。