Python开发英语记忆单词软件 - 优化

修改说明

  1. 每次启动自动导入:__init__中调用了auto_import_words(),该方法会检查words.md是否存在:
    · 存在则导入新单词(去重),并提示新增数量。
    · 不存在则创建示例文件,导入示例单词。
  2. 保留原有数据:导入时仅添加数据库中尚未存在的单词,原有单词的复习记录完全不受影响。
  3. 兼容新格式:解析规则为## 单词 → 下一行(中文意思)→ 下一非空行(例句,可选)。
  4. 手动导入功能保持不变,仍可导入其他文件。

现在您每次更新words.md后重启程序,新添加的单词就会自动加入学习队列。

"""
英语单词记忆软件 - 基于记忆曲线的间隔重复学习系统
支持Markdown格式单词本,手动控制释义显示,自动安排复习计划
"""

import sqlite3
import datetime
import re
import os
import random
from tkinter import *
from tkinter import messagebox, filedialog
from tkinter import ttk


class WordMemoryDB:
    """数据库管理类,处理单词存储和记忆曲线算法"""
    
    def __init__(self, db_path='words.db'):
        self.db_path = db_path
        self.init_database()
    
    def init_database(self):
        """初始化数据库表结构"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS words (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                word TEXT NOT NULL UNIQUE,  -- 添加UNIQUE约束防止重复
                meaning TEXT,
                example TEXT,
                repetitions INTEGER DEFAULT 0,
                ease_factor REAL DEFAULT 2.5,
                interval_days INTEGER DEFAULT 0,
                last_review DATE,
                next_review DATE
            )
        ''')
        conn.commit()
        conn.close()
    
    def import_from_markdown(self, md_path):
        """
        从Markdown文件导入单词(仅添加新词,不清空原有数据)
        新格式:每个单词是一个二级标题(## 单词),后跟中文意思,再跟例句(可选)
        返回新增的单词数量
        """
        if not os.path.exists(md_path):
            raise FileNotFoundError(f"单词本文件不存在: {md_path}")
        
        with open(md_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        
        # 逐行解析
        words_data = []
        i = 0
        while i < len(lines):
            line = lines[i].rstrip('\n')
            if line.strip().startswith('## '):
                # 提取单词
                word = line.strip()[3:].strip()
                if not word:
                    i += 1
                    continue
                
                # 寻找下一非空行作为中文意思
                i += 1
                while i < len(lines) and not lines[i].strip():
                    i += 1
                if i >= len(lines):
                    break  # 文件结束,没有意思
                meaning = lines[i].strip()
                
                # 寻找下一非空行作为例句(可能没有)
                i += 1
                while i < len(lines) and not lines[i].strip():
                    i += 1
                if i < len(lines) and not lines[i].strip().startswith('## '):
                    example = lines[i].strip()
                    i += 1  # 移动到下一行,准备下一轮
                else:
                    example = ""  # 没有例句
                    # 注意:此时i指向的是下一个单词标题或文件末尾,循环会继续
                words_data.append((word, meaning, example))
            else:
                i += 1
        
        # 获取数据库中已存在的单词(用于去重)
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT word FROM words")
        existing_words = {row[0] for row in cursor.fetchall()}
        
        # 插入新单词(去重)
        today = datetime.date.today().isoformat()
        new_count = 0
        for word, meaning, example in words_data:
            if word not in existing_words:
                try:
                    cursor.execute('''
                        INSERT INTO words (word, meaning, example, last_review, next_review)
                        VALUES (?, ?, ?, ?, ?)
                    ''', (word, meaning, example, today, today))
                    new_count += 1
                    existing_words.add(word)
                except sqlite3.IntegrityError:
                    pass
        
        conn.commit()
        conn.close()
        return new_count
    
    def get_due_words(self, exclude_ids=None):
        """
        获取今天需要复习的单词
        exclude_ids: 已在本轮复习过的ID集合
        """
        if exclude_ids is None:
            exclude_ids = set()
        
        today = datetime.date.today().isoformat()
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 构建排除条件
        placeholders = ','.join(['?'] * len(exclude_ids)) if exclude_ids else ''
        query = f'''
            SELECT id, word, meaning, example, repetitions, ease_factor, interval_days
            FROM words
            WHERE next_review <= ? AND id NOT IN ({placeholders})
            ORDER BY random()
            LIMIT 1
        '''
        
        params = [today] + list(exclude_ids) if exclude_ids else [today]
        cursor.execute(query, params)
        result = cursor.fetchone()
        conn.close()
        return result
    
    def update_word_review(self, word_id, quality):
        """
        根据用户反馈更新单词记忆参数(SM-2算法简化版)
        quality: 0=忘记/错误, 1=模糊/困难, 2=正确/记得
        """
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 获取当前单词数据
        cursor.execute('''
            SELECT repetitions, ease_factor, interval_days
            FROM words WHERE id = ?
        ''', (word_id,))
        row = cursor.fetchone()
        if not row:
            conn.close()
            return
        
        repetitions, ease_factor, interval_days = row
        today = datetime.date.today()
        
        if quality >= 2:  # 正确
            if repetitions == 0:
                interval_days = 1
            elif repetitions == 1:
                interval_days = 3
            elif repetitions == 2:
                interval_days = 7
            elif repetitions == 3:
                interval_days = 14
            elif repetitions == 4:
                interval_days = 30
            else:
                interval_days = min(interval_days * 1.5, 365)  # 最长一年
            
            repetitions += 1
            # ease_factor 可适当增加,简化版暂不调整
        else:  # 忘记或模糊
            repetitions = 0
            interval_days = 1 if quality == 1 else 0  # 模糊1天,忘记当天复习
            # ease_factor 降低,简化版暂不调整
        
        # 计算下次复习日期
        next_review = today + datetime.timedelta(days=interval_days)
        
        cursor.execute('''
            UPDATE words
            SET repetitions = ?, ease_factor = ?, interval_days = ?,
                last_review = ?, next_review = ?
            WHERE id = ?
        ''', (repetitions, ease_factor, interval_days, 
              today.isoformat(), next_review.isoformat(), word_id))
        
        conn.commit()
        conn.close()
    
    def get_today_count(self, exclude_ids=None):
        """获取今天待复习单词总数"""
        if exclude_ids is None:
            exclude_ids = set()
        
        today = datetime.date.today().isoformat()
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        placeholders = ','.join(['?'] * len(exclude_ids)) if exclude_ids else ''
        query = f'''
            SELECT COUNT(*) FROM words
            WHERE next_review <= ? AND id NOT IN ({placeholders})
        '''
        params = [today] + list(exclude_ids) if exclude_ids else [today]
        cursor.execute(query, params)
        count = cursor.fetchone()[0]
        conn.close()
        return count


class WordMemoryApp:
    """主应用程序类"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("英语单词记忆助手 - 记忆曲线版")
        self.root.geometry("650x500")
        self.root.resizable(False, False)
        
        # 设置样式
        self.style = ttk.Style()
        self.style.configure('TLabel', font=('微软雅黑', 11))
        self.style.configure('Word.TLabel', font=('微软雅黑', 28, 'bold'))
        
        # 数据库实例
        self.db = WordMemoryDB()
        
        # 当前复习状态
        self.current_word_id = None
        self.current_word_data = None
        self.reviewed_ids = set()  # 本轮已复习的ID
        
        # 默认单词本路径
        self.md_path = "words.md"
        
        # 每次启动自动导入默认单词本中的新词
        self.auto_import_words()
        
        # 创建界面
        self.create_widgets()
        
        # 加载第一个单词
        self.load_next_word()
    
    def auto_import_words(self):
        """每次启动时自动从默认的words.md导入新单词"""
        if os.path.exists(self.md_path):
            try:
                new_count = self.db.import_from_markdown(self.md_path)
                if new_count > 0:
                    messagebox.showinfo("导入成功", f"已自动导入 {new_count} 个新单词")
            except Exception as e:
                messagebox.showerror("错误", f"自动导入失败:{str(e)}")
        else:
            # 文件不存在,创建示例文件并提示
            example_content = """## apple
苹果
This is a red apple.

## book
书
I am reading a book.

## computer
电脑
My computer is fast.

## python
蟒蛇 / Python编程语言
Python is a popular programming language.
"""
            with open(self.md_path, 'w', encoding='utf-8') as f:
                f.write(example_content)
            messagebox.showinfo("提示", f"未找到单词本,已创建示例文件:{self.md_path}")
            # 导入示例单词(但数据库可能已有其他单词,只添加新词)
            try:
                new_count = self.db.import_from_markdown(self.md_path)
                if new_count > 0:
                    messagebox.showinfo("导入成功", f"已自动导入 {new_count} 个示例单词")
            except Exception as e:
                messagebox.showerror("错误", f"自动导入失败:{str(e)}")
    
    def create_widgets(self):
        """创建界面组件"""
        # 顶部信息栏
        top_frame = ttk.Frame(self.root, padding=10)
        top_frame.pack(fill=X)
        
        self.count_label = ttk.Label(top_frame, text="今日剩余: 计算中...")
        self.count_label.pack(side=LEFT)
        
        import_btn = ttk.Button(top_frame, text="重新导入单词本", command=self.import_markdown)
        import_btn.pack(side=RIGHT)
        
        # 中间单词显示区
        mid_frame = ttk.Frame(self.root, padding=20)
        mid_frame.pack(expand=True, fill=BOTH)
        
        self.word_label = ttk.Label(mid_frame, text="", style='Word.TLabel')
        self.word_label.pack(pady=20)
        
        self.meaning_frame = ttk.Frame(mid_frame)
        self.meaning_frame.pack(fill=BOTH, expand=True, pady=10)
        
        self.meaning_label = ttk.Label(self.meaning_frame, text="", 
                                       font=('微软雅黑', 12), 
                                       wraplength=550, justify=LEFT)
        self.meaning_label.pack()
        
        self.example_label = ttk.Label(self.meaning_frame, text="",
                                       font=('微软雅黑', 11, 'italic'),
                                       foreground='gray',
                                       wraplength=550, justify=LEFT)
        self.example_label.pack(pady=5)
        
        # 底部按钮区
        bottom_frame = ttk.Frame(self.root, padding=10)
        bottom_frame.pack(fill=X)
        
        self.show_btn = ttk.Button(bottom_frame, text="显示释义", 
                                   command=self.show_meaning, width=15)
        self.show_btn.pack(side=LEFT, padx=5)
        
        # 评分按钮(初始隐藏)
        self.rating_frame = ttk.Frame(bottom_frame)
        self.rating_frame.pack(side=RIGHT)
        
        self.forget_btn = ttk.Button(self.rating_frame, text="忘记 (0)", 
                                     command=lambda: self.rate_word(0), 
                                     state=DISABLED, width=8)
        self.forget_btn.pack(side=LEFT, padx=2)
        
        self.hard_btn = ttk.Button(self.rating_frame, text="模糊 (1)", 
                                   command=lambda: self.rate_word(1), 
                                   state=DISABLED, width=8)
        self.hard_btn.pack(side=LEFT, padx=2)
        
        self.good_btn = ttk.Button(self.rating_frame, text="记得 (2)", 
                                   command=lambda: self.rate_word(2), 
                                   state=DISABLED, width=8)
        self.good_btn.pack(side=LEFT, padx=2)
    
    def update_count_display(self):
        """更新剩余单词计数"""
        count = self.db.get_today_count(self.reviewed_ids)
        self.count_label.config(text=f"今日剩余复习: {count} 个单词")
    
    def show_meaning(self):
        """显示释义和例句"""
        if self.current_word_data:
            _, _, meaning, example, _, _, _ = self.current_word_data
            self.meaning_label.config(text=f"【释义】 {meaning}")
            self.example_label.config(text=f"📖 {example}" if example else "")
            
            # 切换按钮状态
            self.show_btn.config(state=DISABLED)
            self.forget_btn.config(state=NORMAL)
            self.hard_btn.config(state=NORMAL)
            self.good_btn.config(state=NORMAL)
    
    def hide_meaning(self):
        """隐藏释义"""
        self.meaning_label.config(text="")
        self.example_label.config(text="")
        self.show_btn.config(state=NORMAL)
        self.forget_btn.config(state=DISABLED)
        self.hard_btn.config(state=DISABLED)
        self.good_btn.config(state=DISABLED)
    
    def load_next_word(self):
        """加载下一个待复习单词"""
        # 隐藏当前释义
        self.hide_meaning()
        
        # 获取下一个单词
        word_data = self.db.get_due_words(self.reviewed_ids)
        
        if word_data:
            self.current_word_id = word_data[0]
            self.current_word_data = word_data
            word = word_data[1]
            self.word_label.config(text=word)
            self.reviewed_ids.add(self.current_word_id)
        else:
            # 没有待复习单词了
            self.word_label.config(text="🎉 恭喜!今日复习完成!")
            self.current_word_id = None
            self.current_word_data = None
            self.show_btn.config(state=DISABLED)
        
        self.update_count_display()
    
    def rate_word(self, quality):
        """处理用户评分"""
        if self.current_word_id:
            # 更新数据库
            self.db.update_word_review(self.current_word_id, quality)
            
            # 加载下一个单词
            self.load_next_word()
    
    def import_markdown(self):
        """手动导入Markdown文件(仅添加新词)"""
        filename = filedialog.askopenfilename(
            title="选择单词本文件",
            filetypes=[("Markdown files", "*.md"), ("Text files", "*.txt"), ("All files", "*.*")]
        )
        if filename:
            try:
                new_count = self.db.import_from_markdown(filename)
                # 重置复习状态(新单词立即进入待复习队列)
                self.reviewed_ids.clear()
                self.load_next_word()
                messagebox.showinfo("成功", f"导入完成!新增 {new_count} 个单词")
            except Exception as e:
                messagebox.showerror("错误", f"导入失败:{str(e)}")


def main():
    root = Tk()
    app = WordMemoryApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()

增加删除按钮版本:

"""
英语单词记忆软件 - 基于记忆曲线的间隔重复学习系统
支持Markdown格式单词本,手动控制释义显示,自动安排复习计划
"""

import sqlite3
import datetime
import re
import os
from tkinter import *
from tkinter import messagebox, filedialog
from tkinter import ttk


class WordMemoryDB:
    """数据库管理类,处理单词存储和记忆曲线算法"""
    
    def __init__(self, db_path='words.db'):
        self.db_path = db_path
        self.init_database()
    
    def init_database(self):
        """初始化数据库表结构"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS words (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                word TEXT NOT NULL UNIQUE,
                meaning TEXT,
                example TEXT,
                repetitions INTEGER DEFAULT 0,
                ease_factor REAL DEFAULT 2.5,
                interval_days INTEGER DEFAULT 0,
                last_review DATE,
                next_review DATE
            )
        ''')
        conn.commit()
        conn.close()
    
    def delete_word(self, word_id):
        """根据ID删除单词"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("DELETE FROM words WHERE id = ?", (word_id,))
        affected = cursor.rowcount
        conn.commit()
        conn.close()
        return affected > 0
    
    def import_from_markdown(self, md_path):
        """
        从Markdown文件导入单词(仅添加新词,不清空原有数据)
        新格式:每个单词是一个二级标题(## 单词),后跟中文意思,再跟例句(可选)
        返回新增的单词数量
        """
        if not os.path.exists(md_path):
            raise FileNotFoundError(f"单词本文件不存在: {md_path}")
        
        with open(md_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        
        # 逐行解析
        words_data = []
        i = 0
        while i < len(lines):
            line = lines[i].rstrip('\n')
            if line.strip().startswith('## '):
                # 提取单词
                word = line.strip()[3:].strip()
                if not word:
                    i += 1
                    continue
                
                # 寻找下一非空行作为中文意思
                i += 1
                while i < len(lines) and not lines[i].strip():
                    i += 1
                if i >= len(lines):
                    break
                meaning = lines[i].strip()
                
                # 寻找下一非空行作为例句(可能没有)
                i += 1
                while i < len(lines) and not lines[i].strip():
                    i += 1
                if i < len(lines) and not lines[i].strip().startswith('## '):
                    example = lines[i].strip()
                    i += 1
                else:
                    example = ""
                words_data.append((word, meaning, example))
            else:
                i += 1
        
        # 获取数据库中已存在的单词(用于去重)
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT word FROM words")
        existing_words = {row[0] for row in cursor.fetchall()}
        
        # 插入新单词(去重)
        today = datetime.date.today().isoformat()
        new_count = 0
        for word, meaning, example in words_data:
            if word not in existing_words:
                try:
                    cursor.execute('''
                        INSERT INTO words (word, meaning, example, last_review, next_review)
                        VALUES (?, ?, ?, ?, ?)
                    ''', (word, meaning, example, today, today))
                    new_count += 1
                    existing_words.add(word)
                except sqlite3.IntegrityError:
                    pass
        
        conn.commit()
        conn.close()
        return new_count
    
    def get_due_words(self, exclude_ids=None):
        """获取今天需要复习的单词"""
        if exclude_ids is None:
            exclude_ids = set()
        
        today = datetime.date.today().isoformat()
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        placeholders = ','.join(['?'] * len(exclude_ids)) if exclude_ids else ''
        query = f'''
            SELECT id, word, meaning, example, repetitions, ease_factor, interval_days
            FROM words
            WHERE next_review <= ? AND id NOT IN ({placeholders})
            ORDER BY random()
            LIMIT 1
        '''
        
        params = [today] + list(exclude_ids) if exclude_ids else [today]
        cursor.execute(query, params)
        result = cursor.fetchone()
        conn.close()
        return result
    
    def update_word_review(self, word_id, quality):
        """根据用户反馈更新单词记忆参数"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            SELECT repetitions, ease_factor, interval_days
            FROM words WHERE id = ?
        ''', (word_id,))
        row = cursor.fetchone()
        if not row:
            conn.close()
            return
        
        repetitions, ease_factor, interval_days = row
        today = datetime.date.today()
        
        if quality >= 2:  # 正确
            if repetitions == 0:
                interval_days = 1
            elif repetitions == 1:
                interval_days = 3
            elif repetitions == 2:
                interval_days = 7
            elif repetitions == 3:
                interval_days = 14
            elif repetitions == 4:
                interval_days = 30
            else:
                interval_days = min(interval_days * 1.5, 365)
            repetitions += 1
        else:  # 忘记或模糊
            repetitions = 0
            interval_days = 1 if quality == 1 else 0
        
        next_review = today + datetime.timedelta(days=interval_days)
        
        cursor.execute('''
            UPDATE words
            SET repetitions = ?, ease_factor = ?, interval_days = ?,
                last_review = ?, next_review = ?
            WHERE id = ?
        ''', (repetitions, ease_factor, interval_days, 
              today.isoformat(), next_review.isoformat(), word_id))
        
        conn.commit()
        conn.close()
    
    def get_today_count(self, exclude_ids=None):
        """获取今天待复习单词总数"""
        if exclude_ids is None:
            exclude_ids = set()
        
        today = datetime.date.today().isoformat()
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        placeholders = ','.join(['?'] * len(exclude_ids)) if exclude_ids else ''
        query = f'''
            SELECT COUNT(*) FROM words
            WHERE next_review <= ? AND id NOT IN ({placeholders})
        '''
        params = [today] + list(exclude_ids) if exclude_ids else [today]
        cursor.execute(query, params)
        count = cursor.fetchone()[0]
        conn.close()
        return count


class WordMemoryApp:
    """主应用程序类"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("英语单词记忆助手 - 记忆曲线版")
        self.root.geometry("650x550")
        self.root.resizable(False, False)
        
        self.style = ttk.Style()
        self.style.configure('TLabel', font=('微软雅黑', 11))
        self.style.configure('Word.TLabel', font=('微软雅黑', 28, 'bold'))
        
        self.db = WordMemoryDB()
        self.current_word_id = None
        self.current_word_data = None
        self.reviewed_ids = set()
        self.md_path = "words.md"
        
        self.auto_import_words()
        self.create_widgets()
        self.load_next_word()
    
    def auto_import_words(self):
        """每次启动时自动导入新单词"""
        if os.path.exists(self.md_path):
            try:
                new_count = self.db.import_from_markdown(self.md_path)
                if new_count > 0:
                    messagebox.showinfo("导入成功", f"已自动导入 {new_count} 个新单词")
            except Exception as e:
                messagebox.showerror("错误", f"自动导入失败:{str(e)}")
        else:
            example_content = """## apple
苹果
This is a red apple.

## book
书
I am reading a book.

## computer
电脑
My computer is fast.

## python
蟒蛇 / Python编程语言
Python is a popular programming language.
"""
            with open(self.md_path, 'w', encoding='utf-8') as f:
                f.write(example_content)
            messagebox.showinfo("提示", f"未找到单词本,已创建示例文件:{self.md_path}")
            try:
                new_count = self.db.import_from_markdown(self.md_path)
                if new_count > 0:
                    messagebox.showinfo("导入成功", f"已自动导入 {new_count} 个示例单词")
            except Exception as e:
                messagebox.showerror("错误", f"自动导入失败:{str(e)}")
    
    def create_widgets(self):
        """创建界面组件"""
        top_frame = ttk.Frame(self.root, padding=10)
        top_frame.pack(fill=X)
        
        self.count_label = ttk.Label(top_frame, text="今日剩余: 计算中...")
        self.count_label.pack(side=LEFT)
        
        import_btn = ttk.Button(top_frame, text="重新导入单词本", command=self.import_markdown)
        import_btn.pack(side=RIGHT)
        
        mid_frame = ttk.Frame(self.root, padding=20)
        mid_frame.pack(expand=True, fill=BOTH)
        
        self.word_label = ttk.Label(mid_frame, text="", style='Word.TLabel')
        self.word_label.pack(pady=20)
        
        self.meaning_frame = ttk.Frame(mid_frame)
        self.meaning_frame.pack(fill=BOTH, expand=True, pady=10)
        
        self.meaning_label = ttk.Label(self.meaning_frame, text="", 
                                       font=('微软雅黑', 12), 
                                       wraplength=550, justify=LEFT)
        self.meaning_label.pack()
        
        self.example_label = ttk.Label(self.meaning_frame, text="",
                                       font=('微软雅黑', 11, 'italic'),
                                       foreground='gray',
                                       wraplength=550, justify=LEFT)
        self.example_label.pack(pady=5)
        
        bottom_frame = ttk.Frame(self.root, padding=10)
        bottom_frame.pack(fill=X)
        
        left_buttons = ttk.Frame(bottom_frame)
        left_buttons.pack(side=LEFT)
        
        self.show_btn = ttk.Button(left_buttons, text="显示释义", 
                                   command=self.show_meaning, width=12)
        self.show_btn.pack(side=LEFT, padx=2)
        
        self.delete_btn = ttk.Button(left_buttons, text="删除单词", 
                                     command=self.delete_current_word, width=12)
        self.delete_btn.pack(side=LEFT, padx=2)
        
        self.rating_frame = ttk.Frame(bottom_frame)
        self.rating_frame.pack(side=RIGHT)
        
        self.forget_btn = ttk.Button(self.rating_frame, text="忘记 (0)", 
                                     command=lambda: self.rate_word(0), 
                                     state=DISABLED, width=8)
        self.forget_btn.pack(side=LEFT, padx=2)
        
        self.hard_btn = ttk.Button(self.rating_frame, text="模糊 (1)", 
                                   command=lambda: self.rate_word(1), 
                                   state=DISABLED, width=8)
        self.hard_btn.pack(side=LEFT, padx=2)
        
        self.good_btn = ttk.Button(self.rating_frame, text="记得 (2)", 
                                   command=lambda: self.rate_word(2), 
                                   state=DISABLED, width=8)
        self.good_btn.pack(side=LEFT, padx=2)
    
    def update_count_display(self):
        count = self.db.get_today_count(self.reviewed_ids)
        self.count_label.config(text=f"今日剩余复习: {count} 个单词")
    
    def show_meaning(self):
        if self.current_word_data:
            _, _, meaning, example, _, _, _ = self.current_word_data
            self.meaning_label.config(text=f"【释义】 {meaning}")
            self.example_label.config(text=f"📖 {example}" if example else "")
            self.show_btn.config(state=DISABLED)
            self.delete_btn.config(state=DISABLED)
            self.forget_btn.config(state=NORMAL)
            self.hard_btn.config(state=NORMAL)
            self.good_btn.config(state=NORMAL)
    
    def hide_meaning(self):
        self.meaning_label.config(text="")
        self.example_label.config(text="")
        self.show_btn.config(state=NORMAL)
        self.delete_btn.config(state=NORMAL)
        self.forget_btn.config(state=DISABLED)
        self.hard_btn.config(state=DISABLED)
        self.good_btn.config(state=DISABLED)
    
    def delete_current_word(self):
        """删除当前单词(需确认)"""
        if self.current_word_id is None:
            return
        word = self.current_word_data[1]
        if messagebox.askyesno("确认删除", f"确定要删除单词 \"{word}\" 吗?\n删除后无法恢复。"):
            self.db.delete_word(self.current_word_id)
            if self.current_word_id in self.reviewed_ids:
                self.reviewed_ids.remove(self.current_word_id)
            self.load_next_word()
    
    def load_next_word(self):
        self.hide_meaning()
        word_data = self.db.get_due_words(self.reviewed_ids)
        if word_data:
            self.current_word_id = word_data[0]
            self.current_word_data = word_data
            self.word_label.config(text=word_data[1])
            self.reviewed_ids.add(self.current_word_id)
        else:
            self.word_label.config(text="🎉 恭喜!今日复习完成!")
            self.current_word_id = None
            self.current_word_data = None
            self.show_btn.config(state=DISABLED)
            self.delete_btn.config(state=DISABLED)
        self.update_count_display()
    
    def rate_word(self, quality):
        if self.current_word_id:
            self.db.update_word_review(self.current_word_id, quality)
            self.load_next_word()
    
    def import_markdown(self):
        filename = filedialog.askopenfilename(
            title="选择单词本文件",
            filetypes=[("Markdown files", "*.md"), ("Text files", "*.txt"), ("All files", "*.*")]
        )
        if filename:
            try:
                new_count = self.db.import_from_markdown(filename)
                self.reviewed_ids.clear()
                self.load_next_word()
                messagebox.showinfo("成功", f"导入完成!新增 {new_count} 个单词")
            except Exception as e:
                messagebox.showerror("错误", f"导入失败:{str(e)}")


def main():
    root = Tk()
    app = WordMemoryApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
posted @ 2026-03-12 12:22  hgrun  阅读(16)  评论(0)    收藏  举报