1. 项目概述与核心思路

作为一个长期和代码打交道的开发者,我深知长时间盯着屏幕对眼睛和身体的消耗有多大。有时候一坐就是几个小时,回过神来才觉得眼睛干涩、脖子僵硬。市面上有不少屏幕时间管理软件,但要么功能复杂,要么提醒方式生硬,用几次就关掉了。最近看到一个挺有意思的项目,一个13岁的小开发者用Python做了一个“屏幕时间监察官”,它的核心创意在于用带点幽默和“压迫感”的AI语音(比如模拟“愤怒的亚洲妈妈”口吻)和图片来提醒你该休息了,而不是冷冰冰的弹窗。这个点子让我眼前一亮,决定沿着这个思路,结合我自己的开发经验,从头到尾实现并优化一个更健壮、更实用的版本。这不仅仅是一个编程练习,更是打造一个真正能帮到自己和同事的健康小工具。

这个程序的核心目标很明确:在后台安静运行,从你开启电脑或启动程序时开始计时。随着连续使用电脑的时间累积,程序会分阶段、逐步升级提醒的“强度”。初期可能是温和的语音提示,后期则会加入图片、GIF甚至循环播放严厉的语音,直到你决定休息并关闭程序或电脑。技术栈选择Python,因为它拥有极其丰富的库,能让我们轻松实现定时任务、音频播放和网页/图片展示。我们将主要用到 time 模块进行计时, winsound 模块(Windows平台)或跨平台的 playsound pygame 库来播放警告音频,以及 webbrowser 模块来打开本地或网络的图片/动图进行视觉提醒。整个项目的价值在于,它用一种略带趣味性和强干预性的方式,将健康用眼的理念转化为可执行、可感知的日常程序。

2. 项目核心设计与架构解析

2.1 功能逻辑与流程设计

在动手写代码之前,我们必须把程序的工作流程想清楚。一个可靠的屏幕时间监控程序,其核心逻辑应该是一个清晰的状态机。参考原项目的思路并加以完善,我设计了以下工作流程:

  1. 初始化与启动 :程序启动,初始化计时器( start_time = time.time() ),并加载配置(如总时长阈值、各阶段提醒的时间点、对应的音频/图片文件路径)。
  2. 后台循环监控 :程序进入一个主循环,在后台持续运行。在循环中,它不断计算自开始计时以来经过的时间( elapsed_time = time.time() - start_time )。
  3. 阶段判断与触发提醒 :将经过的时间与预设的多个时间阈值进行比较。例如:
    • 30分钟:触发第一阶段提醒,播放一段温和的语音(如“已经看屏幕30分钟啦,起来活动一下脖子吧”)。
    • 50分钟:触发第二阶段提醒,播放语气更紧迫的语音,并弹出一张休息提示的图片。
    • 60分钟(或用户设定的专注时长):触发最终警告,循环播放严厉的语音提醒,并可能打开一个全屏或无法轻易关闭的警告页面,直到用户主动中断程序。
  4. 提醒执行 :根据判断结果,调用相应的函数来执行“提醒”动作,如播放 wav 音频文件、用默认浏览器打开一张提醒图片的URL或本地文件路径。
  5. 循环与退出 :主循环以一定的间隔(如每秒)检查一次时间,避免CPU占用过高。退出条件可以是用户手动关闭程序,或者(如果我们设计的话)在触发最终警告后,用户完成了一段休息时间,程序重置计时。

这个流程的关键在于“渐进式”和“非侵入式”到“强干预式”的过渡。一开始的提醒要友好,避免引起反感;后期的提醒则需要足够有力,能打断用户当前的沉浸状态。

2.2 技术选型与工具准备

原项目提到了PyCharm和 winsound ,这是一个很好的起点,但为了程序的健壮性和跨平台潜力,我们需要考虑更多。

  • 开发环境与IDE :任何Python环境都可以。PyCharm、VS Code、甚至Jupyter Notebook(用于原型验证)都行。我个人习惯用VS Code,轻量且插件丰富。关键是创建一个独立的虚拟环境( venv ),方便管理依赖。

    # 在项目目录下创建虚拟环境
    python -m venv venv
    # 激活虚拟环境 (Windows)
    venv\Scripts\activate
    # 激活虚拟环境 (macOS/Linux)
    source venv/bin/activate
    
  • 核心库选择

    • 计时与循环 :Python标准库中的 time 模块是唯一选择, time.time() 获取时间戳既简单又精准。
    • 音频播放
      • winsound :仅适用于Windows,最简单,但功能有限(主要播放 .wav )。原项目使用它,对于纯Windows环境是OK的。
      • playsound :一个跨平台的纯Python库,可以播放 MP3 WAV 等格式,API极其简单( playsound(‘sound.mp3’) )。这是实现跨平台兼容性的推荐选择。
      • pygame :功能强大的多媒体库,可以更精细地控制音频(如音量、循环播放),但重量也更大。如果我们需要复杂的音频混合或循环播放警告, pygame 是更好的选择。
    • 视觉提醒
      • webbrowser :Python标准库, webbrowser.open(‘file:///path/to/image.jpg’) 可以用默认图片查看器打开本地图片, webbrowser.open(‘https://…’) 可以打开网络图片。它的优点是简单、依赖少。缺点是会弹出浏览器或图片查看器窗口,可能会干扰工作。
      • PIL (Pillow) + tkinter / PyQt :如果想创建自定义的、更美观的提醒窗口(例如一个始终置顶的半透明弹窗),则需要用到图形界面库。这复杂度会高很多,但体验也更好。
    • 配置管理 :使用 json yaml 文件来存储用户配置(如提醒时间点、音频文件路径、总时长等),这样不用修改代码就能调整行为。

注意 :考虑到项目的初衷是简单、有趣且易于理解和修改,我们将主要采用 time + playsound (跨平台) + webbrowser 的方案。如果确定只在Windows上使用, winsound 也是一个轻量选项。

  • 素材准备(AI语音与图片)
    • AI语音 :原项目作者使用了在线TTS服务。现在这类服务很多,如国内的百度AI开放平台、阿里云、腾讯云都有免费的TTS额度,国外有Google Cloud TTS、Microsoft Azure TTS等。我们可以用这些服务生成不同语气(温和、提醒、警告)的语音文件,保存为 mp3 wav 格式。 切记要遵守服务条款,生成的内容需符合公序良俗。
    • 图片/GIF :可以自己制作或寻找一些有趣的、表达“休息”、“眼睛疲劳”主题的图片或动图。例如,一个旋转的“休息一下”的标语,或者一个搞笑的、捂着眼睛的表情包。将这些素材放在项目目录的 assets 文件夹下。

3. 分步实现与核心代码详解

3.1 项目结构与配置定义

首先,我们来搭建一个清晰的项目结构。这能让代码更易维护。

screen_time_inspector/
├── config.json       # 配置文件
├── main.py           # 主程序入口
├── requirements.txt  # 项目依赖
└── assets/           # 资源文件夹
    ├── audio/
    │   ├── reminder_30min.mp3
    │   ├── warning_50min.mp3
    │   └── final_warning_60min.mp3
    └── images/
        ├── take_a_break.png
        └── eye_exercise.gif

config.json 文件内容示例:

{
    "total_duration_minutes": 60,
    "reminder_stages": [
        {
            "trigger_minute": 30,
            "audio_file": "assets/audio/reminder_30min.mp3",
            "image_file": "",
            "message": "已经连续使用电脑30分钟,建议远眺20秒。"
        },
        {
            "trigger_minute": 50,
            "audio_file": "assets/audio/warning_50min.mp3",
            "image_file": "assets/images/take_a_break.png",
            "message": "您已使用50分钟!请立刻起身活动,做一下伸展运动。"
        },
        {
            "trigger_minute": 60,
            "audio_file": "assets/audio/final_warning_60min.mp3",
            "image_file": "assets/images/eye_exercise.gif",
            "is_final": true,
            "loop_audio": true,
            "blocking": true
        }
    ],
    "check_interval_seconds": 1
}

这个配置文件定义了总时长、多个提醒阶段(触发时间、对应的音频和图片)、以及程序检查的时间间隔。 is_final , loop_audio , blocking 等字段用于控制最终警告的行为。

3.2 核心计时与状态监控循环

主程序 main.py 的核心是一个循环,它不断检查经过的时间并触发相应事件。

import time
import json
import os
from pathlib import Path
# 我们将使用playsound进行跨平台音频播放
try:
    from playsound import playsound
    USE_PLAYSOUND = True
except ImportError:
    # 如果playsound安装失败,且是Windows,则回退到winsound
    import sys
    if sys.platform == 'win32':
        import winsound
        USE_PLAYSOUND = False
    else:
        print("错误:非Windows系统请安装 'playsound' 库。")
        sys.exit(1)
import webbrowser

class ScreenTimeInspector:
    def __init__(self, config_path='config.json'):
        self.load_config(config_path)
        self.start_time = time.time()
        self.triggered_stages = set() # 记录已触发过的阶段,避免重复触发
        self.is_running = True
        self.final_warning_active = False

    def load_config(self, config_path):
        """加载配置文件"""
        with open(config_path, 'r', encoding='utf-8') as f:
            self.config = json.load(f)
        # 将分钟转换为秒,便于内部计算
        self.total_duration = self.config['total_duration_minutes'] * 60
        self.check_interval = self.config['check_interval_seconds']
        for stage in self.config['reminder_stages']:
            stage['trigger_second'] = stage['trigger_minute'] * 60

    def play_audio(self, audio_path):
        """播放音频文件,处理跨平台兼容性"""
        if not os.path.exists(audio_path):
            print(f"警告:音频文件不存在 {audio_path}")
            return
        try:
            if USE_PLAYSOUND:
                playsound(audio_path)
            else:
                # Windows winsound 只支持 .wav
                if audio_path.endswith('.wav'):
                    winsound.PlaySound(audio_path, winsound.SND_FILENAME)
                else:
                    print(f"警告:winsound不支持播放 {audio_path},请转换为.wav格式或安装playsound。")
        except Exception as e:
            print(f"播放音频时出错: {e}")

    def show_image(self, image_path):
        """使用默认程序打开图片或GIF"""
        if not os.path.exists(image_path):
            print(f"警告:图片文件不存在 {image_path}")
            return
        # 使用 file:// 协议打开本地文件
        webbrowser.open(f'file://{os.path.abspath(image_path)}')

    def execute_reminder_stage(self, stage):
        """执行单个提醒阶段的所有动作"""
        print(f"\n[提醒] {stage['message']}")
        if stage.get('audio_file'):
            self.play_audio(stage['audio_file'])
        if stage.get('image_file'):
            self.show_image(stage['image_file'])

        # 如果是最终警告阶段,启动一个阻塞循环
        if stage.get('is_final', False):
            self.final_warning_active = True
            print("!!! 最终警告已激活 !!! 请立即离开电脑休息。")
            if stage.get('loop_audio', False) and stage.get('audio_file'):
                # 注意:这里循环播放会阻塞主线程。更优解是使用线程,但为简化,我们先这样处理。
                # 在实际中,可以考虑用 pygame.mixer 实现后台循环播放。
                while self.final_warning_active:
                    self.play_audio(stage['audio_file'])
                    time.sleep(5) # 每5秒重复一次警告语音

    def check_and_trigger(self):
        """检查时间并触发相应的提醒阶段"""
        current_time = time.time()
        elapsed_seconds = current_time - self.start_time

        # 检查是否超过总时长,触发最终阶段(如果配置了)
        if elapsed_seconds >= self.total_duration:
            final_stages = [s for s in self.config['reminder_stages'] if s.get('is_final')]
            for final_stage in final_stages:
                if final_stage['trigger_second'] not in self.triggered_stages:
                    self.execute_reminder_stage(final_stage)
                    self.triggered_stages.add(final_stage['trigger_second'])
            return

        # 检查每个提醒阶段
        for stage in self.config['reminder_stages']:
            trigger_sec = stage['trigger_second']
            # 如果当前时间超过该阶段触发点,且该阶段未被触发过
            if elapsed_seconds >= trigger_sec and trigger_sec not in self.triggered_stages:
                self.execute_reminder_stage(stage)
                self.triggered_stages.add(trigger_sec)

    def run(self):
        """主运行循环"""
        print(f"屏幕时间监察官已启动。总时长设定为 {self.config['total_duration_minutes']} 分钟。")
        print("程序将在后台运行,按 Ctrl+C 可终止。")
        try:
            while self.is_running and not self.final_warning_active:
                self.check_and_trigger()
                # 休眠指定间隔,降低CPU占用
                time.sleep(self.check_interval)
        except KeyboardInterrupt:
            print("\n程序被用户中断。")
        finally:
            print("屏幕时间监察官已退出。")

if __name__ == "__main__":
    inspector = ScreenTimeInspector()
    inspector.run()

这段代码构建了一个完整的监控程序骨架。 ScreenTimeInspector 类封装了所有功能:加载配置、计时、播放音频、展示图片以及主循环。使用类的方式使得代码结构清晰,未来也容易扩展(例如添加GUI、网络同步等功能)。

3.3 音频与视觉提醒的实现细节

音频和视觉提醒是用户体验的核心。上面代码中已经实现了基本功能,但还有一些细节可以优化。

  • 音频播放的优化

    • 异步播放 playsound winsound.PlaySound 默认都是阻塞的,即播放完毕前程序会卡住。对于较长的提醒音频,这会导致主循环暂停。我们可以使用线程来异步播放。
    import threading
    def play_audio_async(audio_path):
        def _play():
            playsound(audio_path)
        thread = threading.Thread(target=_play)
        thread.daemon = True # 设置为守护线程,主程序退出时自动结束
        thread.start()
    
    • 音量与格式 playsound 不支持调节音量。如果需要更精细的控制, pygame.mixer 是更好的选择,它可以设置音量、循环播放,并且也是跨平台的。
  • 视觉提醒的优化

    • 使用 webbrowser.open 的问题 :它会打开系统默认的图片查看器或浏览器。如果用户正在全屏工作,这个新窗口可能会被盖住,起不到提醒作用。
    • 更醒目的提醒方案
      1. 使用 tkinter 创建简单弹窗 :虽然会引入GUI依赖,但可以创建始终置顶( topmost )的窗口。
      import tkinter as tk
      def show_popup(image_path):
          root = tk.Tk()
          root.attributes('-topmost', True) # 置顶
          root.overrideredirect(True) # 无边框窗口
          # 加载并显示图片 (需要PIL/Pillow)
          from PIL import Image, ImageTk
          img = Image.open(image_path)
          photo = ImageTk.PhotoImage(img)
          label = tk.Label(root, image=photo)
          label.pack()
          # 10秒后自动关闭
          root.after(10000, root.destroy)
          root.mainloop()
      
      1. 使用系统通知 :对于macOS ( osascript )、Linux ( notify-send ) 和 Windows ( win10toast 库),可以发送原生系统通知,更轻量且不干扰当前窗口。

实操心得 :在初期原型验证时,用 webbrowser 是最快的。但如果你想做一个真正“讨人嫌”、无法忽视的提醒,学习一点 tkinter 来做个置顶小弹窗是非常值得的。或者,结合系统通知和音频,也是一种平衡的方案。

4. 功能增强与个性化定制

基础版本已经能工作,但我们可以让它更智能、更贴心。

4.1 实现可配置化与用户交互

目前的配置是写死在 json 文件里的。我们可以做一个简单的命令行接口(CLI)或配置文件生成器,让用户无需编辑JSON就能设置。

# cli_config.py - 一个简单的命令行配置工具
import json
import sys

def create_config():
    print("=== 屏幕时间监察官配置向导 ===")
    total_min = int(input("请输入您希望的总专注时长(分钟): "))
    stages = []
    add_stage = True
    while add_stage:
        print(f"\n--- 添加第 {len(stages)+1} 个提醒阶段 ---")
        trigger = int(input("  在多少分钟时触发?: "))
        audio = input("  音频文件路径(留空则无): ").strip()
        image = input("  图片/GIF文件路径(留空则无): ").strip()
        message = input("  提醒消息: ")
        is_final = input("  是否为最终警告阶段?(y/N): ").lower() == 'y'
        stage = {
            "trigger_minute": trigger,
            "audio_file": audio if audio else "",
            "image_file": image if image else "",
            "message": message,
            "is_final": is_final
        }
        if is_final:
            stage["loop_audio"] = input("  是否循环播放警告音频?(y/N): ").lower() == 'y'
        stages.append(stage)
        add_stage = input("是否继续添加提醒阶段?(y/N): ").lower() == 'y'

    config = {
        "total_duration_minutes": total_min,
        "reminder_stages": stages,
        "check_interval_seconds": 1
    }
    with open('my_config.json', 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2, ensure_ascii=False)
    print("配置已保存至 'my_config.json'。")

if __name__ == "__main__":
    create_config()

这样,用户运行 python cli_config.py 就可以通过问答方式生成自己的配置文件。

4.2 休息计时与自动重置

一个完整的健康周期应该是“工作 -> 提醒 -> 休息 -> 重置”。我们可以在最终警告触发后,不仅循环提醒,还启动一个“强制休息”计时器。

# 在 ScreenTimeInspector 类中添加
def start_break_timer(self, break_minutes=5):
    """启动休息计时器"""
    print(f"\n[系统] 进入强制休息时间,时长 {break_minutes} 分钟。")
    break_end = time.time() + break_minutes * 60
    while time.time() < break_end:
        remaining = int(break_end - time.time())
        mins, secs = divmod(remaining, 60)
        # 可以在这里显示一个倒计时,或者播放舒缓的音乐
        time.sleep(1)
    print("[系统] 休息时间结束!计时器将重置。")
    self.reset_timer()

def reset_timer(self):
    """重置所有计时和状态"""
    self.start_time = time.time()
    self.triggered_stages.clear()
    self.final_warning_active = False
    print("计时器已重置。")

然后在 execute_reminder_stage 中,如果遇到最终阶段,除了循环警告,还可以调用 start_break_timer

4.3 系统托盘与后台静默运行

对于需要长时间后台运行的程序,一个系统托盘图标是更好的选择,它让程序存在感更低,也方便用户随时暂停、退出或查看状态。我们可以使用 pystray 库(跨平台)来实现。

# 这是一个高级功能示例,需要安装 pystray 和 PIL
# pip install pystray Pillow
import pystray
from PIL import Image, ImageDraw
import threading

def create_tray_icon(inspector):
    """创建系统托盘图标和菜单"""
    # 创建一个简单的图标
    image = Image.new('RGB', (64, 64), color='white')
    draw = ImageDraw.Draw(image)
    draw.ellipse([16, 16, 48, 48], fill='red', outline='black')
    draw.text((24, 24), 'ST', fill='white') # ST for Screen Time

    # 定义菜单项
    menu = (
        pystray.MenuItem(f"已运行: {int(time.time()-inspector.start_time)//60}分", lambda: None, enabled=False),
        pystray.MenuItem("暂停监控", lambda: toggle_pause(inspector)),
        pystray.MenuItem("立即重置", lambda: inspector.reset_timer()),
        pystray.MenuItem("退出", lambda: stop_program(inspector, icon)),
    )
    icon = pystray.Icon("screen_time_inspector", image, "屏幕时间监察官", menu)
    return icon

def toggle_pause(inspector):
    inspector.is_running = not inspector.is_running
    status = "已暂停" if not inspector.is_running else "已恢复"
    print(f"[系统] {status}")

def stop_program(inspector, icon):
    inspector.is_running = False
    icon.stop()
    print("程序正在退出...")

# 在主程序中,需要将主循环放在一个线程中运行,以免阻塞系统托盘
if __name__ == "__main__":
    inspector = ScreenTimeInspector()
    # 启动监控循环线程
    monitor_thread = threading.Thread(target=inspector.run)
    monitor_thread.daemon = True
    monitor_thread.start()
    # 启动系统托盘
    icon = create_tray_icon(inspector)
    icon.run()

这样,程序启动后会在系统托盘区显示一个图标,右键点击可以查看状态、暂停、重置或退出,非常优雅。

5. 常见问题排查与优化建议

在实际开发和运行中,你可能会遇到以下问题。这里我整理了一份排查清单和优化建议。

5.1 音频播放失败

  • 问题 :程序运行无错误,但没有声音。
  • 排查
    1. 检查文件路径 :确保 config.json 中的音频文件路径正确。使用绝对路径或相对于主程序 main.py 的路径。打印出程序尝试加载的完整路径进行检查。
    2. 检查文件格式 :如果使用 winsound ,它只支持 .wav 格式。确保你的音频文件是未压缩的PCM WAV格式。 playsound 支持 mp3 wav ,但需要系统有对应的解码器。
    3. 检查音量与设备 :确认系统音量未静音,且输出设备选择正确。
    4. 检查库安装 :确保 playsound 已正确安装 ( pip install playsound )。在Windows上,它依赖系统媒体播放器;在macOS/Linux上,它可能依赖 gstreamer 等。
  • 解决方案
    • 统一使用 .wav 格式以确保最大兼容性。可以使用在线转换工具或 pydub 库进行转换。
    • 尝试使用 pygame.mixer 作为备选方案,它通常更可靠。
    import pygame
    pygame.mixer.init()
    pygame.mixer.music.load(‘audio.wav’)
    pygame.mixer.music.play()
    

5.2 图片/GIF无法打开或显示异常

  • 问题 webbrowser.open 没有反应,或打开了错误的程序。
  • 排查
    1. 检查文件路径和权限 :同音频文件。
    2. 检查默认程序 webbrowser.open 使用系统默认关联程序打开文件。确保图片格式(如 .png , .jpg , .gif )有默认的查看器。
    3. URL格式 :打开本地文件时,路径需要是 file:// 开头的URL。 os.path.abspath 可以获取绝对路径。
  • 解决方案
    • 使用 subprocess 调用特定命令打开图片,可能更可控(但牺牲跨平台性)。
    import subprocess, os, sys
    if sys.platform == 'darwin': # macOS
        subprocess.call(['open', image_path])
    elif sys.platform == 'win32': # Windows
        os.startfile(image_path)
    else: # Linux
        subprocess.call(['xdg-open', image_path])
    
    • 如前所述,考虑使用 tkinter 或系统通知来展示提醒,避免依赖外部程序。

5.3 程序CPU占用过高或过低

  • 问题 :程序导致电脑风扇狂转,或者提醒严重延迟。
  • 原因与解决
    • 主循环休眠间隔 ( check_interval_seconds ) 设置得太小(如0.01秒),会导致循环执行过于频繁,消耗CPU。通常设置为0.5到2秒之间是完全足够的,对提醒精度几乎没有影响。
    • 阻塞操作 :如果音频播放是阻塞的(且音频很长),主循环会卡住。务必使用 异步播放 (如线程)。
    • 最终警告循环 :如果最终警告阶段是 while 循环播放音频且没有休眠,会占用大量CPU。在循环内添加 time.sleep()

5.4 如何实现开机自启动?

这是一个常见的需求,让程序在用户登录后自动运行。

  • Windows
    1. 创建程序的快捷方式。
    2. Win + R ,输入 shell:startup ,打开启动文件夹。
    3. 将快捷方式拖入此文件夹。
  • macOS
    1. 系统设置 -> 通用 -> 登录项。
    2. 点击“+”号,添加你的Python脚本或打包后的应用。
  • Linux (GNOME)
    1. /etc/xdg/autostart/ 或用户目录的 ~/.config/autostart/ 下创建一个 .desktop 文件。
    2. 文件内容示例:
      [Desktop Entry]
      Type=Application
      Name=Screen Time Inspector
      Exec=python3 /path/to/your/main.py
      Hidden=false
      NoDisplay=false
      X-GNOME-Autostart-enabled=true
      

重要提醒 :实现开机自启动前,请确保你的程序已经过充分测试,不会导致系统启动错误或冲突。最好提供一个清晰的选项让用户选择是否启用自启动。

5.5 提升提醒的“有效性”与“趣味性”

原项目的“愤怒的亚洲妈妈”创意是趣味性的核心。我们可以把这个点子发扬光大:

  • 语音内容库 :不要只用一两条语音。建立一个语音库,每次触发时随机选择一条,增加新鲜感。内容可以从温和劝导到幽默吐槽再到“严厉警告”。
  • 视觉素材库 :同样,建立一个图片/GIF库,随机展示。可以是可爱的动物、励志名言、搞笑的梗图,或者简单的护眼科普图。
  • 互动式休息 :在强制休息期间,弹窗可以显示一些简单的、能在座位上完成的伸展运动动画或指导,鼓励用户真正动起来。
  • 数据统计 :记录每天的使用数据和休息次数,每周生成一个简单的报告,让用户看到自己的进步。

这个项目的魅力在于它介于工具和玩具之间。通过Python,我们不仅实现了一个健康辅助工具,更探索了如何用代码与人进行有趣、有效的交互。从简单的计时循环,到音频播放、图形界面、系统集成,每一步都涉及不同的编程知识点,是一个非常好的综合练习。希望你在实现它的过程中,既能保护好自己的眼睛,也能享受到编程的乐趣。

更多推荐