桌面定时语音播报程序

起因:年后开始上班,一直坐电脑旁,时间长了颈椎和腰部都不舒服,感觉要隔一段时间提醒自己锻炼一下,但是又找不到合适的方法,最后想到用程序来播报语音提醒的方式来让自己起来活动。

使用场景

定时提醒

  • 例如每小时提醒用户休憩、喝水等。

  • 背景音乐:定时播放背景音乐,营造氛围。

  • 自动化任务:定时播放特定音频,用于自动化任务。

实现的功能如下:

1. 定时播放音频:

用户可以选择本地音频文件(

.mp3 和

.wav

格式)。

设置时间间隔(以分钟为单位),程序会按照设定的时间间隔定时播放音频。

桌面定时语音播报程序

2.

试听功能

用户可以在选择音频文件后立即试听,确保音频文件能够正常播放。

桌面定时语音播报程序

3. 保存和加载设置:

程序会保存用户选择的音频文件和时间间隔,并在下次启动时自动加载。

桌面定时语音播报程序

4.

开机自启动

用户可以选择是否让程序随系统自动启动。

如果通过开机自启动启动,程序会自动隐藏到状态栏。

桌面定时语音播报程序





5. 系统托盘支持:

用户可以选择将程序最小化到系统托盘,而不是直接关闭。

托盘图标支持自定义图标,并提供“恢复窗口”和“退出”选项。

桌面定时语音播报程序

桌面定时语音播报程序

运行界面如图

桌面定时语音播报程序

全部代码如下:

import tkinter as tk
from tkinter import filedialog, messagebox
import pygame
import json
import os
import threading
import sys
import getpass
from PIL import Image, ImageDraw
import pystray

# 初始化pygame
pygame.mixer.init()

# 配置文件路径
CONFIG_FILE = "config.json"

class AudioTimerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("定时语音播报")
        
        # 设置默认窗口大小
        self.root.geometry("500x330")  # 宽度500像素,高度330像素
        
        # 设置程序图标
        self.set_icon()
        
        # 将窗口定位到屏幕正中心
        self.center_window()
        
        # 加载上次的设置
        self.load_config()
        
        # 创建界面元素
        self.create_widgets()
        
        # 启动定时器
        self.start_timer()
        
        # 重写关闭按钮事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        
        # 检查是否通过开机自启动启动
        if self.is_autostart_launch() and not self.is_first_launch():
            self.minimize_to_tray()  # 自动隐藏到状态栏

    def create_widgets(self):
        # 选择音频文件按钮
        self.file_button = tk.Button(self.root, text="选择音频文件", command=self.select_file)
        self.file_button.pack(pady=10)
        
        # 显示当前选择的文件
        self.file_label = tk.Label(self.root, text=f"当前文件: {os.path.basename(self.audio_file) if self.audio_file else '未选择'}")
        self.file_label.pack()
        
        # 试听按钮
        self.preview_button = tk.Button(self.root, text="试听", command=self.preview_audio, state=tk.DISABLED)
        self.preview_button.pack(pady=10)
        
        # 时间间隔输入框
        self.interval_label = tk.Label(self.root, text="时间间隔 (分钟):")
        self.interval_label.pack(pady=10)
        
        # 使用 Spinbox 替换 Entry
        self.interval_spinbox = tk.Spinbox(self.root, from_=1, to=120, increment=1, width=5)
        self.interval_spinbox.insert(0, str(self.interval // 60))  # 将秒转换为分钟
        self.interval_spinbox.pack()
        
        # 保存设置按钮
        self.save_button = tk.Button(self.root, text="保存设置", command=self.save_settings)
        self.save_button.pack(pady=20)
        
        # 开机自启动选项
        self.autostart_var = tk.BooleanVar(value=self.check_autostart())
        self.autostart_check = tk.Checkbutton(self.root, text="开机自启动", variable=self.autostart_var, command=self.toggle_autostart)
        self.autostart_check.pack(pady=10)

    def select_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("音频文件", "*.mp3 *.wav")])
        if file_path:
            self.audio_file = file_path
            self.file_label.config(text=f"当前文件: {os.path.basename(self.audio_file)}")
            self.preview_button.config(state=tk.NORMAL)  # 启用试听按钮
            self.save_settings()

    def preview_audio(self):
        if self.audio_file:
            try:
                print(f"正在试听音频文件: {self.audio_file}")  # 调试信息
                pygame.mixer.music.load(self.audio_file)
                pygame.mixer.music.play()
                print("试听成功")  # 调试信息
            except Exception as e:
                print(f"试听失败: {e}")  # 调试信息
                messagebox.showerror("错误", f"无法试听音频: {e}")

    def start_timer(self):
        if self.audio_file:
            self.play_audio()
        self.root.after(self.interval * 1000, self.start_timer)

    def play_audio(self):
        try:
            print(f"正在加载音频文件: {self.audio_file}")  # 调试信息
            pygame.mixer.music.load(self.audio_file)
            pygame.mixer.music.play()
            print("音频播放成功")  # 调试信息
        except Exception as e:
            print(f"音频播放失败: {e}")  # 调试信息
            messagebox.showerror("错误", f"无法播放音频: {e}")

    def save_settings(self):
        try:
            interval_minutes = int(self.interval_spinbox.get())
            if interval_minutes < 1:
                messagebox.showerror("错误", "时间间隔不能小于1分钟")
                return
            self.interval = interval_minutes * 60  # 将分钟转换为秒
            config = {
                "audio_file": self.audio_file,
                "interval": self.interval
            }
            with open(CONFIG_FILE, "w") as f:
                json.dump(config, f)
            messagebox.showinfo("成功", "设置已保存!")  # 提示保存成功
            self.start_timer()  # 重新启动定时器
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字")

    def load_config(self):
        try:
            with open(CONFIG_FILE, "r") as f:
                config = json.load(f)
                self.audio_file = config.get("audio_file", "")
                self.interval = config.get("interval", 360)  # 默认值为360秒(6分钟)
        except FileNotFoundError:
            self.audio_file = ""
            self.interval = 360  # 默认值为360秒(6分钟)

    def on_close(self):
        # 弹出选择框,让用户选择最小化到托盘或退出
        choice = messagebox.askyesnocancel("关闭程序", "是否最小化到托盘?
点击'是'最小化,'否'退出程序")
        if choice is True:  # 最小化到托盘
            self.minimize_to_tray()
        elif choice is False:  # 退出
            self.root.destroy()  # 关闭程序
        # 如果点击撤销,则不做任何操作

    def minimize_to_tray(self):
        # 隐藏主窗口
        self.root.withdraw()
        
        # 创建系统托盘图标
        self.create_tray_icon()

    def create_tray_icon(self):
        # 加载自定义图标文件
        def create_image():
            try:
                # 获取图标文件路径
                if getattr(sys, 'frozen', False):  # 判断是否打包成 exe
                    base_path = sys._MEIPASS
                else:
                    base_path = os.path.dirname(__file__)
                icon_path = os.path.join(base_path, "tray_icon.ico")
                # 加载图标文件
                image = Image.open(icon_path)
                return image
            except Exception as e:
                print(f"无法加载托盘图标: {e}")
                # 如果图标文件不存在,使用默认图标
                image = Image.new('RGB', (64, 64), 'white')
                dc = ImageDraw.Draw(image)
                dc.rectangle((16, 16, 48, 48), fill='blue')
                return image
        
        # 托盘菜单
        menu = (
            pystray.MenuItem('恢复窗口', self.restore_from_tray),
            pystray.MenuItem('退出', self.quit_program),
        )
        
        # 创建托盘图标
        self.tray_icon = pystray.Icon("AudioTimer", create_image(), "定时语音播报", menu)
        self.tray_icon.run()

    def restore_from_tray(self, icon, item):
        # 恢复主窗口
        self.root.deiconify()
        # 停止托盘图标
        self.tray_icon.stop()

    def quit_program(self, icon, item):
        # 退出程序
        self.tray_icon.stop()
        self.root.destroy()

    def toggle_autostart(self):
        if self.autostart_var.get():
            self.enable_autostart()
        else:
            self.disable_autostart()

    def enable_autostart(self):
        # 获取当前用户的启动目录
        startup_folder = os.path.join(os.getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")
        # 获取当前脚本的路径
        script_path = os.path.abspath(sys.argv[0])
        # 创建快捷方式
        shortcut_path = os.path.join(startup_folder, "AudioTimer.lnk")
        try:
            import winshell
            from win32com.client import Dispatch
            shell = Dispatch('WScript.Shell')
            shortcut = shell.CreateShortCut(shortcut_path)
            shortcut.Targetpath = script_path
            shortcut.WorkingDirectory = os.path.dirname(script_path)
            shortcut.save()
            print("开机自启动已启用")
        except ImportError:
            messagebox.showerror("错误", "无法启用开机自启动,请确保已安装 `pywin32` 和 `winshell`")

    def disable_autostart(self):
        # 获取当前用户的启动目录
        startup_folder = os.path.join(os.getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")
        # 删除快捷方式
        shortcut_path = os.path.join(startup_folder, "AudioTimer.lnk")
        if os.path.exists(shortcut_path):
            os.remove(shortcut_path)
            print("开机自启动已禁用")

    def check_autostart(self):
        # 检查是否已设置开机自启动
        startup_folder = os.path.join(os.getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")
        shortcut_path = os.path.join(startup_folder, "AudioTimer.lnk")
        return os.path.exists(shortcut_path)

    def is_autostart_launch(self):
        # 检查是否通过开机自启动启动
        startup_folder = os.path.join(os.getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")
        shortcut_path = os.path.join(startup_folder, "AudioTimer.lnk")
        if os.path.exists(shortcut_path):
            # 获取当前脚本的路径
            script_path = os.path.abspath(sys.argv[0])
            # 检查快捷方式的目标路径是否与当前脚本路径一致
            try:
                from win32com.client import Dispatch
                shell = Dispatch('WScript.Shell')
                shortcut = shell.CreateShortCut(shortcut_path)
                return shortcut.Targetpath == script_path
            except ImportError:
                pass
        return False

    def is_first_launch(self):
        # 检查是否是第一次启动
        first_launch_file = "first_launch.txt"
        if not os.path.exists(first_launch_file):
            with open(first_launch_file, "w") as f:
                f.write("1")
            return True
        return False

    def set_icon(self):
        # 设置程序图标
        icon_path = "app.ico"  # 图标文件路径
        if os.path.exists(icon_path):
            self.root.iconbitmap(icon_path)
        else:
            print(f"图标文件 {icon_path} 不存在,请确保图标文件与程序在同一目录下。")

    def center_window(self):
        # 获取屏幕尺寸
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        
        # 计算窗口居中的位置
        window_width = 500  # 窗口宽度
        window_height = 330  # 窗口高度
        x = (screen_width // 2) - (window_width // 2)
        y = (screen_height // 2) - (window_height // 2)
        
        # 设置窗口位置
        self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")

if __name__ == "__main__":
    root = tk.Tk()
    app = AudioTimerApp(root)
    root.mainloop() 

打包说明:
–add-data “tray_icon.ico;.”:将 tray_icon.ico 文件包含在打包的 exe 文件中,;. 表明将文件放在与 exe 一样的目录下。
–icon=app.ico:为 exe 文件设置图标。

pyinstaller --onefile --windowed --add-data "tray_icon.ico;." --icon=app.ico audio_timer.py

最后打包成exe文件,在windows上运行。

本程序是一个简易使用的定时语音播报工具,适合需要定时播放音频的场景。通过图形界面和系统托盘支持,用户可以方便地管理和操作程序。如果需要进一步扩展功能,可以在此基础上进行优化和开发。

附上已经打包好的程序放在网盘,需要的请自行下载:

链接: https://pan.baidu.com/s/1LcDpAmhmllraMWM89iYVHg?pwd=be62 提取码: be62

链接:https://pan.quark.cn/s/8abb75988466 提取码:CJes

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 共11条

请登录后发表评论