Python + Tkinter + pyttsx3实现的桌面版英语学习工具

Python + Tkinter + pyttsx3实现的桌面版英语学习工具

在多行文本框输入英文句子,双击其中的英文单词,给出英文读音和中文含义和音标。

本程序查询本地词典数据。通过菜单栏"文件"->"打开词典编辑器"进入编辑界面。

词典数据存储在独立的dictionary.json文件中,这个文件需要和程序文件在同一文件夹中,否则将自动建立一个。

编辑器实现了完整的CRUD(创建、读取、更新、删除)功能

添加单词:直接填写所有字段后点击"添加单词"

编辑单词:从列表选择单词 -> 修改字段 -> 点击"保存修改"

删除单词:从列表选择单词 -> 点击"删除选中"

pyttsx3 是一个文本到语音(Text-to-Speech, TTS)转换库,它允许你在 Python 程序中将文本转换为语音输出。它是第三方库需要安装使用。

在cmd中,使用 Python 包安装命令安装:pip install pyttsx3

若安装了多个python版本,X.Y代表Python版本,多余的部分舍弃如3.8.1取3.8,3.10.5取3.10,即只取第二个点前的部分。仅安装了一个python版本不需要。pip命令默认会连接在国外的python官方服务器下载,速度可能比较慢,使用镜像网址可以加快速度:-i 镜像网址

py -3.12 -m pip install 第三方库名 -i https://pypi.tuna.tsinghua.edu.cn/simple

py -3.12 -m pip install pyttsx3 -i https://pypi.tuna.tsinghua.edu.cn/simple

运行效果:

源码如下:

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import json
import os
import pyttsx3class DictionaryEditor:def __init__(self, master, dictionary, save_callback):self.master = masterself.dictionary = dictionaryself.save_callback = save_callbackself.selected_word = Nonemaster.title("词典编辑器")master.geometry("600x400")# 创建界面组件self.create_widgets()self.update_word_list()def create_widgets(self):# 单词列表框架list_frame = ttk.Frame(self.master)list_frame.pack(side=tk.LEFT, padx=10, pady=10, fill=tk.BOTH, expand=True)self.word_list = tk.Listbox(list_frame, selectmode=tk.SINGLE)self.word_list.pack(fill=tk.BOTH, expand=True)self.word_list.bind('<<ListboxSelect>>', self.on_word_select)# 控制按钮框架btn_frame = ttk.Frame(list_frame)btn_frame.pack(pady=5)ttk.Button(btn_frame, text="刷新列表", command=self.update_word_list).pack(side=tk.LEFT, padx=2)ttk.Button(btn_frame, text="删除选中", command=self.delete_word).pack(side=tk.LEFT, padx=2)# 编辑区框架edit_frame = ttk.Frame(self.master)edit_frame.pack(side=tk.RIGHT, padx=10, pady=10, fill=tk.BOTH, expand=True)# 输入字段ttk.Label(edit_frame, text="单词:").grid(row=0, column=0, sticky=tk.W)self.word_entry = ttk.Entry(edit_frame)self.word_entry.grid(row=0, column=1, pady=5, sticky=tk.EW)ttk.Label(edit_frame, text="音标:").grid(row=1, column=0, sticky=tk.W)self.phonetic_entry = ttk.Entry(edit_frame)self.phonetic_entry.grid(row=1, column=1, pady=5, sticky=tk.EW)ttk.Label(edit_frame, text="翻译:").grid(row=2, column=0, sticky=tk.W)self.translation_entry = ttk.Entry(edit_frame)self.translation_entry.grid(row=2, column=1, pady=5, sticky=tk.EW)# 操作按钮btn_frame = ttk.Frame(edit_frame)btn_frame.grid(row=3, column=0, columnspan=2, pady=10)ttk.Button(btn_frame, text="添加单词", command=self.add_word).pack(side=tk.LEFT, padx=5)ttk.Button(btn_frame, text="保存修改", command=self.save_changes).pack(side=tk.LEFT, padx=5)def update_word_list(self):self.word_list.delete(0, tk.END)for word in sorted(self.dictionary.keys()):self.word_list.insert(tk.END, word)def on_word_select(self, event):selection = self.word_list.curselection()if selection:self.selected_word = self.word_list.get(selection[0])self.load_word_data()def load_word_data(self):data = self.dictionary.get(self.selected_word, {})self.word_entry.delete(0, tk.END)self.phonetic_entry.delete(0, tk.END)self.translation_entry.delete(0, tk.END)self.word_entry.insert(0, self.selected_word)self.phonetic_entry.insert(0, data.get('phonetic', ''))self.translation_entry.insert(0, data.get('translation', ''))def validate_input(self):word = self.word_entry.get().strip().lower()phonetic = self.phonetic_entry.get().strip()translation = self.translation_entry.get().strip()if not word:messagebox.showwarning("输入错误", "单词不能为空")return Falseif not translation:messagebox.showwarning("输入错误", "翻译不能为空")return Falsereturn Truedef add_word(self):if not self.validate_input():returnnew_word = self.word_entry.get().strip().lower()if new_word in self.dictionary:messagebox.showwarning("添加失败", "该单词已存在")returnself.dictionary[new_word] = {'phonetic': self.phonetic_entry.get().strip(),'translation': self.translation_entry.get().strip()}self.save_data()self.update_word_list()messagebox.showinfo("成功", "单词已添加")def save_changes(self):if not self.selected_word or not self.validate_input():returnnew_word = self.word_entry.get().strip().lower()# 检查是否修改了单词if new_word != self.selected_word:if new_word in self.dictionary:messagebox.showwarning("修改失败", "目标单词已存在")return# 删除旧条目并创建新条目del self.dictionary[self.selected_word]self.selected_word = new_wordself.dictionary[new_word] = {'phonetic': self.phonetic_entry.get().strip(),'translation': self.translation_entry.get().strip()}self.save_data()self.update_word_list()messagebox.showinfo("成功", "修改已保存")def delete_word(self):if not self.selected_word:returnif messagebox.askyesno("确认删除", f"确定要删除 '{self.selected_word}' 吗?"):del self.dictionary[self.selected_word]self.save_data()self.selected_word = Noneself.update_word_list()messagebox.showinfo("成功", "单词已删除")def save_data(self):self.save_callback()class EnglishLearningApp:def __init__(self, master):self.master = mastermaster.title("英语学习助手")master.geometry("800x600")# 初始化语音引擎self.engine = pyttsx3.init()self.engine.setProperty('rate', 150)# 创建菜单self.create_menu()# 加载词典数据self.dictionary_file = "dictionary.json"self.dictionary = self.load_dictionary()# 创建界面组件self.create_widgets()# 添加缺失的 load_dictionary 方法def load_dictionary(self):"""从JSON文件加载词典数据"""try:if not os.path.exists(self.dictionary_file):# 如果文件不存在,创建默认词典default_data = {"hello": {"translation": "你好", "phonetic": "/həˈloʊ/"},"world": {"translation": "世界", "phonetic": "/wɜːrld/"}}with open(self.dictionary_file, 'w', encoding='utf-8') as f:json.dump(default_data, f, indent=2, ensure_ascii=False)return default_datawith open(self.dictionary_file, 'r', encoding='utf-8') as f:data = json.load(f)# 验证数据格式if not all(['translation' in v and 'phonetic' in v for v in data.values()]):raise ValueError("词典文件格式不正确")return dataexcept Exception as e:messagebox.showerror("初始化错误", f"无法加载词典:{str(e)}")self.master.destroy()  # 关闭程序exit(1)def create_widgets(self):# 输入文本框self.text_input = tk.Text(self.master,height=10,wrap=tk.WORD,font=('Arial', 12),borderwidth=2,relief="groove")self.text_input.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)self.text_input.bind("<Double-Button-1>", self.on_double_click)# 结果显示区域self.result_frame = ttk.Frame(self.master)self.result_frame.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)self.result_label = ttk.Label(self.result_frame,text="双击单词,出现查询结果:",font=('Arial', 12, 'bold'))self.result_label.pack(anchor=tk.W)self.result_text = tk.Text(self.result_frame,height=6,wrap=tk.WORD,font=('Arial', 12),bg='#f0f8ff',borderwidth=2,relief="groove")self.result_text.pack(fill=tk.BOTH, expand=True)# 发音按钮self.speak_button = ttk.Button(self.master,text="播放发音",command=self.speak_word)self.speak_button.pack(pady=5)def on_double_click(self, event):try:# 获取选中的单词self.text_input.tag_remove("sel", "1.0", tk.END)self.text_input.tag_add("sel", "current wordstart", "current wordend")selected_word = self.text_input.get("sel.first", "sel.last").lower()if selected_word:# 查询词典result = self.dictionary.get(selected_word)if result:self.show_result(selected_word, result)self.current_word = selected_wordelse:self.result_text.delete(1.0, tk.END)self.result_text.insert(tk.END, f"未找到 '{selected_word}' 的释义")except Exception as e:messagebox.showerror("错误", f"发生错误:{str(e)}")def show_result(self, word, data):self.result_text.config(state=tk.NORMAL)self.result_text.delete(1.0, tk.END)result_str = (f"单词:{word}\n\n"f"音标:{data['phonetic']}\n\n"f"中文释义:{data['translation']}")self.result_text.insert(tk.END, result_str)self.result_text.config(state=tk.DISABLED)def speak_word(self):if hasattr(self, 'current_word'):self.engine.say(self.current_word)self.engine.runAndWait()        def create_menu(self):menubar = tk.Menu(self.master)# 文件菜单file_menu = tk.Menu(menubar, tearoff=0)file_menu.add_command(label="打开词典编辑器", command=self.open_editor)file_menu.add_separator()file_menu.add_command(label="退出", command=self.master.destroy) menubar.add_cascade(label="文件", menu=file_menu)self.master.config(menu=menubar)def open_editor(self):editor_window = tk.Toplevel(self.master)DictionaryEditor(editor_window, self.dictionary, self.save_dictionary)def save_dictionary(self):try:with open(self.dictionary_file, 'w', encoding='utf-8') as f:json.dump(self.dictionary, f, indent=2, ensure_ascii=False)except Exception as e:messagebox.showerror("保存失败", f"无法保存词典文件:{str(e)}")if __name__ == "__main__":root = tk.Tk()app = EnglishLearningApp(root)root.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/11798.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验六 项目二 简易信号发生器的设计与实现 (HEU)

声明&#xff1a;代码部分使用了AI工具 实验六 综合考核 Quartus 18.0 FPGA 5CSXFC6D6F31C6N 1. 实验项目 要求利用硬件描述语言Verilog&#xff08;或VHDL&#xff09;、图形描述方式、IP核&#xff0c;结合数字系统设计方法&#xff0c;在Quartus开发环境下&#xff…

17.3.4 颜色矩阵

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵&#xff08;Matrix&#xff09;是一个按照长方阵列排列的复数或实数集合&#xff0c;类似于数组。 由…

音视频入门基础:RTP专题(8)——使用Wireshark分析RTP

一、引言 通过Wireshark可以抓取RTP数据包&#xff0c;该软件可以从Wireshark Go Deep 下载。 二、通过Wireshark抓取RTP数据包 首先通过FFmpeg将一个媒体文件转推RTP&#xff0c;生成RTP流&#xff1a; ffmpeg -re -stream_loop -1 -i input.mp4 -vcodec copy -an -f rtp …

【leetcode100】路径总和Ⅲ

1、题目描述 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点…

解锁数据结构密码:层次树与自引用树的设计艺术与API实践

1. 引言&#xff1a;为什么选择层次树和自引用树&#xff1f; 数据结构是编程中的基石之一&#xff0c;尤其是在处理复杂关系和层次化数据时&#xff0c;树形结构常常是最佳选择。层次树&#xff08;Hierarchical Tree&#xff09;和自引用树&#xff08;Self-referencing Tree…

python-leetcode-二叉树的层序遍历

102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right from coll…

c++可变参数详解

目录 引言 库的基本功能 va_start 宏: va_arg 宏 va_end 宏 va_copy 宏 使用 处理可变参数代码 C11可变参数模板 基本概念 sizeof... 运算符 包扩展 引言 在C编程中&#xff0c;处理不确定数量的参数是一个常见的需求。为了支持这种需求&#xff0c;C标准库提供了 &…

w191教师工作量管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

Vuex状态管理

1、Vuex 是什么&#xff1f; Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 简单理解 Vuex可以帮我们管理全局的属性&#xff0c;并且是是响应式的&…

DBASE DBF数据库文件解析

基于Java实现DBase DBF文件的解析和显示 JDK19编译运行&#xff0c;实现了数据库字段和数据解析显示。 首先解析数据库文件头代码 byte bytes[] Files.readAllBytes(Paths.get(file));BinaryBufferArray bis new BinaryBufferArray(bytes);DBF dbf new DBF();dbf.VersionN…

亚博microros小车-原生ubuntu支持系列:20 ROS Robot APP建图

依赖工程 新建工程laserscan_to_point_publisher src/laserscan_to_point_publisher/laserscan_to_point_publisher/目录下新建文件laserscan_to_point_publish.py #!/usr/bin/env python3import rclpy from rclpy.node import Node from geometry_msgs.msg import PoseStam…

冷启动+强化学习:DeepSeek-R1 的原理详解——无需监督数据的推理能力进化之路

本文基于 DeepSeek 官方论文进行分析,论文地址为:https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf 有不足之处欢迎评论区交流 原文翻译 在阅读和理解一篇复杂的技术论文时,逐字翻译是一个重要的步骤。它不仅能帮助我们准确把握作者的原意,还能为后续…

优选算法的灵动之章:双指针专题(一)

个人主页&#xff1a;手握风云 专栏&#xff1a;算法 一、双指针算法思想 双指针算法主要用于处理数组、链表等线性数据结构中的问题。它通过设置两个指针&#xff0c;在数据结构上进行遍历和操作&#xff0c;从而实现高效解决问题。 二、算法题精讲 2.1. 查找总价格为目标值…

数据结构之栈和队列(超详解)

文章目录 概念与结构栈队列 代码实现栈栈是否为空&#xff0c;取栈顶数据、栈的有效个数 队列入队列出队列队列判空&#xff0c;取队头、队尾数据&#xff0c;队列的有效个数 算法题解有效的括号用队列实现栈用栈实现队列复用 设计循环队列数组结构实现循环队列构造、销毁循环队…

解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作

目录 前言1. ALL_SYNONYMS 视图2. ALL_VIEWS 视图3. 扩展 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. ALL_SYNONYMS 视图 在 Oracle 数据库中&#xff0c;同义词&#xff08;Synonym&#xff09;是对数…

DeepSeek-R1 本地部署教程(超简版)

文章目录 一、DeepSeek相关网站二、DeepSeek-R1硬件要求三、本地部署DeepSeek-R11. 安装Ollama1.1 Windows1.2 Linux1.3 macOS 2. 下载和运行DeepSeek模型3. 列出本地已下载的模型 四、Ollama命令大全五、常见问题解决附&#xff1a;DeepSeek模型资源 一、DeepSeek相关网站 官…

【C语言入门】解锁核心关键字的终极奥秘与实战应用(二)

目录 一、sizeof 1.1. 作用 2.2. 代码示例 二、const 2.1. 作用 2.2. 代码示例 三、signed 和 unsigned 3.1. 作用 3.2. 代码示例 四、struct、union、enum 4.1. struct&#xff08;结构体&#xff09; 4.1.1. 作用 4.1.2. 代码示例 4.2. union&#xff08;联合…

如何确认Linux嵌入式系统的触摸屏对应的是哪个设备文件?如何查看系统中所有的输入设备?输入设备的设备文件有什么特点?

Linux嵌入式系统的输入设备的设备文件有什么特点&#xff1f; 在 Linux 中&#xff0c;所有的输入设备&#xff08;如键盘、鼠标、触摸屏等&#xff09;都会被内核识别为 输入事件设备&#xff0c;并在 /dev/input/ 目录下创建相应的 设备文件&#xff0c;通常是&#xff1a; …

ESP32-c3实现获取土壤湿度(ADC模拟量)

1硬件实物图 2引脚定义 3使用说明 4实例代码 // 定义土壤湿度传感器连接的模拟输入引脚 const int soilMoisturePin 2; // 假设连接到GPIO2void setup() {// 初始化串口通信Serial.begin(115200); }void loop() {// 读取土壤湿度传感器的模拟值int sensorValue analogRead…

Hive:窗口函数(1)

窗口函数 窗口函数OVER()用于定义一个窗口&#xff0c;该窗口指定了函数应用的数据范围 对窗口数据进行分区 partition by 必须和over () 一起使用, distribute by经常和sort by 一起使用,可以不和over() 一起使用.DISTRIBUTE BY决定了数据如何分布到不同的Reducer上&#xf…