• 【python小项目】用python写一个小工具——番茄钟


    用python写一个小工具——番茄钟

    最近听到朋友说在用番茄钟,有点兴趣也想下载一个来用用,后面仔细一想这玩意做起来也不难,索性自己顺手写一个算了,在这里也分享给大家了

    一、功能简述

    番茄钟即番茄工作法,番茄工作法是简单易行的时间管理工具,使用番茄工作法即一个番茄时间共30分钟,25分钟工作,5分钟休息;

    特点一:番茄时长有三档

    因为这个工具本人也是考虑到每个人情况不一样,不一定25分钟就适合自己,所以将番茄钟时长设为30min/45min/60min三档,自由选择

    特点二:番茄统计功能

    特点三:休息期间会自动播放放松音乐,当然不喜欢也支持禁止播放放松音乐,休息时间结束后,音乐也会自动停止(意味着又要开始“搬砖”了)

    特点四:番茄钟结束后,会有蜂鸣音提示,并且跳出弹框

    番茄钟界面

    二、使用到的主要模块

    tkinter:用于界面设计

    winsound:用于调用蜂鸣器提示音

    pygame:用于音乐播放

    time:时间相关的格式转换

    三、核心模块代码分析

    代码的主要思路是主函数中,利用tkinter模块布局界面、按钮、标签等组件,然后将番茄钟、休息两大核心功能封装到函数中,一旦点击对应的按钮,即开启一个新线程用于执行对应的功能,同时通过全局变量thread_flag来保持永远只有主线程和功能线程2个线程,避免多次点击,产生多个线程同时运行,造成番茄钟混乱;

    1、番茄钟模块
    ## 创建番茄计时函数
    def tomato_clock(remain_time):    
        # 如果在休息时间未结束就开启番茄钟,则停止音乐
        pygame.mixer.music.pause()
        
        # 用来提醒用户选择番茄钟时长,为选择的话,就跳出函数,结束线程
        if remain_time == 0:
            lb3.configure(text='请先选择番茄钟时长')
            return
        print(remain_time)
        
        # gmtime这里是将时间转化为计算机可处理的时间格式即time_t到tm类型的转换;不是重点,知道是格式转化即可
        # strptime()函数将字符串转换为datetime
        begin_time = time.strftime('%M:%S', time.gmtime(remain_time))
        
        # 将时间内容打印到界面上
        lb2.configure(text=begin_time)
        lb3.configure(text='总时间/剩余时间')
        
        # 用于保证番茄钟线程或者休息线程只有一个能存在,这个也是本人觉得比较巧的一个点
        global thread_flag
        if thread_flag:
            thread_flag = False
        else:
            thread_flag = True
        tmp_thread_flag = thread_flag
        
        # 时间变化部分
        for i in range(remain_time):
            # 如果收到休息线程导致的thread_flag标志位的变化,则退出线程
            if tmp_thread_flag != thread_flag:
                return
            
            remain_time -= 1
            remain_time_str = time.strftime('/ %M:%S', time.gmtime(remain_time))
            
            # 将时钟实时更新到界面上
            lb1.configure(text=remain_time_str)
            root.update()
            time.sleep(1)
            
            #时间到了,开启蜂鸣提醒与提示框提醒
            if remain_time == 0:
                Beep(500, 800)
                tomato_count()
                mymsg()
        lb1.configure(text=begin_time)
        
        #使用者确认后,自动进入休息模式
        relax()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    2、音乐控制函数
    # 音乐控制函数,用来控制是否允许休息时播放音乐,其实本质只是静音而已,狗头.jpg
    # 在定义时,music_flag已经初始化True,代表运行休息时播放音乐
    def music_allow():
        global music_flag		#声明全局变量
        # 如果已经是True(即不禁止音乐时),勾选了按钮,则music_flag 变为 False,禁止音乐
        if music_flag:
            music_flag = False
            pygame.mixer.music.set_volume(0.0)
        else:
            # 代表取消勾选,不禁止音乐
            music_flag = True
            pygame.mixer.music.set_volume(0.5)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    3、main中的按钮部分
    # 每当按钮点击后,就会产生一个线程,执行对应的功能,和主线程并行
    # 以防止单线程的话,进入番茄钟或者休息时,界面中的其他功能按钮失效
    
    # 开启番茄钟按钮,使用lambda构造匿名函数是因为command后接的函数如果有参数会失效,这点本人也不清楚,没去深究,直接匿名函数走去
    # 同时daemon=True,即将线程设为守护线程,解决主线程退出时,其他线程不正常退出的问题
    Button1 = tk.Button(root, text='开启一个番茄', bg='orange', fg='black', font='Verdana 13 bold',width=15,
        height=1, command=lambda: threading.Thread(target=tomato_clock, daemon=True,args=(var.get(),)).start())
    Button1.place(x=70, y=150)
    
    # 休息一下按钮
    Button2 = tk.Button(root, text='休息一下', bg='cornflowerblue', fg='black', font='Verdana 13 bold',
                            width=15,height=1,command=lambda:threading.Thread(target=relax,daemon=True).start())
    Button2.place(x=70, y=200)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    四、整体代码

    # -*- coding:utf-8 -*-
    import tkinter as tk
    import tkinter.messagebox
    from winsound import Beep
    import threading
    import sys
    import pygame
    import time
    
    # 用于统计完成的番茄钟个数
    count = 0
    # 线程切换标志
    thread_flag = True
    # 音乐开关标志
    music_flag = True
    
    # 调用Tk()创建主窗口
    root = tk.Tk()
    # 给主窗口起一个名字,也就是窗口的名字
    root.title('Rio的番茄钟')
    # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x"
    root.geometry('460x300')
    root.configure(bg='Tomato')
    
    
    # 创建完成计时后的弹窗
    def mymsg():
        try:
            tk.messagebox.showinfo("提示", "恭喜完成一个番茄钟!!记得休息一下")
        except Exception as e:
            print(type(e), e)
            sys.exit()
    
    # 休息结束弹窗
    def mymsg2():
        tk.messagebox.showinfo("提示", "休息完毕!")
    
    # 创建番茄计时函数
    # strptime()函数将字符串转换为datetime
    def tomato_clock(remain_time):
        # 如果在休息时间未结束就开启番茄钟,则停止音乐
        pygame.mixer.music.pause()
        # 避免未进行番茄钟时长选择
        if remain_time == 0:
            lb3.configure(text='请先选择番茄钟时长')
            return
        print(remain_time)
        begin_time = time.strftime('%M:%S', time.gmtime(remain_time))
        lb2.configure(text=begin_time)
        lb3.configure(text='总时间/剩余时间')
        global thread_flag
        if thread_flag:
            thread_flag = False
        else:
            thread_flag = True
        tmp_thread_flag = thread_flag
        for i in range(remain_time):
            if tmp_thread_flag != thread_flag:
                return
            remain_time -= 1
            remain_time_str = time.strftime('/ %M:%S', time.gmtime(remain_time))
            lb1.configure(text=remain_time_str)
            root.update()
            time.sleep(1)
            if remain_time == 0:
                Beep(500, 800)
                tomato_count()
                mymsg()
        lb1.configure(text=begin_time)
        relax()
    
    
    # 创建番茄计数的函数
    def tomato_count():
        global count
        count += 1
        lb4.configure(text=count)
    
    # 创建休息时间函数
    def relax():
        remain_time = 480   # 休息8分钟
        begin_time = time.strftime('%M:%S', time.gmtime(remain_time))
        lb2.configure(text=begin_time)
        lb3.configure(text='总时间/剩余时间')
    
        # 线程标志,用于结束旧线程
        global thread_flag
        if thread_flag:
            thread_flag = False
        else:
            thread_flag = True
        tmp_thread_flag = thread_flag
        pygame.mixer.music.play(-1)
        for i in range(remain_time):
            if tmp_thread_flag != thread_flag:
                return
            remain_time -= 1
            remain_time_str = time.strftime('/ %M:%S', time.gmtime(remain_time))
            lb1.configure(text=remain_time_str)
            root.update()
            time.sleep(1)
            if remain_time == 0:
                pygame.mixer.music.pause()
                mymsg2()
        lb1.configure(text=begin_time)
    
    # 音乐控制函数
    def music_allow():
        global music_flag
        # 如果已经是True(即不禁止音乐时),勾选了按钮,则music_flag 变为 False,禁止音乐
        if music_flag:
            music_flag = False
            pygame.mixer.music.set_volume(0.0)
        else:
            music_flag = True
            pygame.mixer.music.set_volume(0.5)
    
    if __name__ == "__main__":
    
        #音乐初始化
        pygame.mixer.init()
        # 异常抛出,防止没有放音乐文件
        try:
            pygame.mixer.music.load('music.mp3')
        except Exception as e:
            print(type(e), e)
            tk.messagebox.showinfo("提示", "无文件music.mp3或改文件路径不对")
            sys.exit()
        pygame.mixer.music.set_volume(0.5)
        # 创建变量
        var = tk.IntVar()
        # 给变量赋初值为30
        var.set(30)
    
        # 番茄动态计时
        lb1 = tk.Label(root, text='0', bg='Tomato', fg='white', font='Verdana 16 bold', width=7, height=1)
        lb1.place(x=130, y=100)
    
        # 番茄固定时间
        lb2 = tk.Label(root, text='0', bg='Tomato', fg='white', font='Verdana 16 bold', width=5, height=1)
        lb2.place(x=60, y=100)
    
        # 剩余时间/总时间
        lb3 = tk.Label(root, text=' ', bg='Tomato', fg='white', font='Verdana 16 bold', width=14, height=2)
        lb3.place(x=50, y=44)
    
        # 番茄个数显示
        lb4 = tk.Label(root, text='0', bg='Tomato', fg='white', font='Verdana 16 bold', width=7, height=1)
        lb4.place(x=90, y=20)
    
        # 左上角的 番茄:
        lb5 = tk.Label(root, text='已积累番茄:', bg='Tomato', fg='white', font='Verdana 16 bold', width=8, height=1)
        lb5.place(x=5, y=20)
    
        # 按钮
        ##创造一个frame来收纳按钮
        fr1 = tk.LabelFrame(root,bg='LightGreen',text='选择番茄钟时长', relief='groove', bd=1,)
        fr1.pack(side='right')
        r1 = tk.Radiobutton(fr1, text='30min', variable=var, bg='LightGreen', value=1800)
        r1.pack()
        r2 = tk.Radiobutton(fr1, text='45min', variable=var, bg='LightGreen', value=2700)
        r2.pack()
        r3 = tk.Radiobutton(fr1, text='60min', variable=var, bg='LightGreen', value=3599)
        r3.pack()
        Checkbutton = tk.Checkbutton(fr1, text="是否禁止音乐", fg='black', bg='LightGreen', command=music_allow)
        Checkbutton.pack()
    
        # 开启一个番茄
        #利用多线程,避免进入番茄钟后,退出按钮失效
        Button1 = tk.Button(root, text='开启一个番茄', bg='orange', fg='black', font='Verdana 13 bold',width=15,
                          height=1, command=lambda: threading.Thread(target=tomato_clock, daemon=True,args=(var.get(),)).start())
        Button1.place(x=70, y=150)
    
        # 休息一下
        Button2 = tk.Button(root, text='休息一下', bg='cornflowerblue', fg='black', font='Verdana 13 bold',
                            width=15, height=1, command=lambda: threading.Thread(target=relax, daemon=True).start())
        Button2.place(x=70, y=200)
    
        # 添加按钮,以及按钮的文本,并通过command 参数设置关闭窗口的功能
        button = tk.Button(root, text="退出", fg='black', bg='YellowGreen', width=15, command=root.quit)
        # 将按钮放置在主窗口内
        button.place(x=105, y=250)
    
        #开启主循环,让窗口处于显示状态
        root.mainloop()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186

    最后

    当然这个项目也不是完全从0开始,有借鉴了python 用tkinter 做一个简易番茄钟的代码,其实本人更多的是丰富和优化。也欢迎大家在我写的部分继续优化丰富;也欢迎大家批评正。

    我也将代码以及生成的.exe文件打包成压缩包上传了,用python写一个小工具-番茄钟可以直接下载使用该工具,有需要可自行下载,.exe文件在压缩包的dist文件夹中,感谢支持

  • 相关阅读:
    免编译,运行单文件Java程序【JDK16+】
    C语言PTA练习题(期末考试成绩排名,新生舞会,约瑟夫游戏(序号+姓名+密码),排队点名)
    海外媒体发稿:海外汽车媒体推广9个方式解析
    手把手教你部署nginx+php —— k8s从入门到高并发系列教程 (一)
    小DEMO:css制作圆滑梯形按钮
    GaoNeng:我是如何为OpenTiny贡献新组件的?
    基于FPGA的误码检测
    面对同样复杂的测试任务为什么大老很快能梳理解决方案,阿里十年测试工程师道出其中的技巧
    Spring Cloud Gateway快速入门(二)——断言工厂
    2024年抖店的市场已经饱和,小白不适合入局了?真实现状如下
  • 原文地址:https://blog.csdn.net/weixin_44517500/article/details/128129974