|
|
import tkinter as tk
|
|
|
from tkinter import messagebox
|
|
|
import random
|
|
|
import pymysql
|
|
|
|
|
|
class LoginPage(tk.Toplevel):
|
|
|
def __init__(self, master=None):
|
|
|
super().__init__(master)
|
|
|
self.title("登录")
|
|
|
self.geometry("200x200")
|
|
|
|
|
|
self.username_var = tk.StringVar()
|
|
|
self.password_var = tk.StringVar()
|
|
|
|
|
|
tk.Label(self, text="用户名:").pack()
|
|
|
tk.Entry(self, textvariable=self.username_var).pack()
|
|
|
|
|
|
tk.Label(self, text="密码:").pack()
|
|
|
tk.Entry(self, show="*", textvariable=self.password_var).pack()
|
|
|
|
|
|
tk.Button(self, text="登录", command=self.login).pack(pady=10)
|
|
|
|
|
|
def login(self):
|
|
|
username = self.username_var.get()
|
|
|
password = self.password_var.get()
|
|
|
if username == "a" and password == "123456":
|
|
|
self.master.destroy() # 关闭主窗口(如果有),这里假设直接关闭自身也行,取决于实际结构
|
|
|
MainApp().mainloop() # 登录成功后实例化MainApp并启动其主循环
|
|
|
else:
|
|
|
messagebox.showerror("错误", "用户名或密码错误!") # 登录失败,保持登录界面打开供用户重试
|
|
|
|
|
|
|
|
|
|
|
|
class MainApp(tk.Tk):
|
|
|
def __init__(self):
|
|
|
super().__init__()
|
|
|
self.title("单词学习")
|
|
|
self.geometry("200x200")
|
|
|
|
|
|
# 创建三个按钮
|
|
|
tk.Button(self, text="学习新单词", command=self.open_window1).pack(fill=tk.X, padx=10, pady=5)
|
|
|
tk.Button(self, text="复习单词", command=self.open_window2).pack(fill=tk.X, padx=10, pady=5)
|
|
|
tk.Button(self, text="易错单词查看", command=self.open_window3).pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
|
|
def open_window1(self):
|
|
|
Window1(self)
|
|
|
|
|
|
def open_window2(self):
|
|
|
Window2(self)
|
|
|
|
|
|
def open_window3(self):
|
|
|
Window3(self)
|
|
|
|
|
|
|
|
|
class Window1(tk.Toplevel):
|
|
|
def __init__(self, master):
|
|
|
super().__init__(master)
|
|
|
self.title("单词学习界面")
|
|
|
|
|
|
# 初始化MySQL数据库连接
|
|
|
self.conn = pymysql.connect(
|
|
|
host="localhost", # MySQL服务器地址
|
|
|
user="root", # 数据库用户名
|
|
|
password="21412030117", # 数据库密码
|
|
|
database="word", # 数据库名
|
|
|
charset='utf8mb4', # 字符编码,根据需要调整
|
|
|
cursorclass=pymysql.cursors.DictCursor # 使用字典游标,方便通过列名访问数据
|
|
|
)
|
|
|
|
|
|
self.cursor = self.conn.cursor()
|
|
|
|
|
|
self.word_frame = tk.Frame(self)
|
|
|
self.word_frame.pack(padx=10, pady=10)
|
|
|
|
|
|
self.next_button = tk.Button(self, text="下一个单词", command=self.show_next_word)
|
|
|
self.next_button.pack(side=tk.RIGHT, padx=5, pady=5)
|
|
|
self.prev_button = tk.Button(self, text="上一个单词") # 实现逻辑待补充
|
|
|
self.prev_button.pack(side=tk.LEFT, padx=5, pady=5)
|
|
|
|
|
|
self.show_next_word() # 初始显示一个单词
|
|
|
|
|
|
def show_next_word(self):
|
|
|
# 查询并获取一个未学习的单词
|
|
|
query = ("SELECT word, meaning FROM words WHERE learned = 0 ORDER BY RAND() LIMIT 1")
|
|
|
self.cursor.execute(query)
|
|
|
word_row = self.cursor.fetchone()
|
|
|
if word_row:
|
|
|
word, meaning = word_row['word'], word_row['meaning'] # 使用字典访问列
|
|
|
self.display_word(word, meaning)
|
|
|
# 标记该单词为已学习
|
|
|
self.mark_word_as_learned(word)
|
|
|
else:
|
|
|
messagebox.showinfo("提示", "所有单词都已学习过!")
|
|
|
|
|
|
def display_word(self, word, meaning):
|
|
|
"""显示单词及其意义"""
|
|
|
for widget in self.word_frame.winfo_children():
|
|
|
widget.destroy()
|
|
|
|
|
|
tk.Label(self.word_frame, text=f"单词: {word}").pack(anchor=tk.W)
|
|
|
tk.Label(self.word_frame, text=f"意义: {meaning}").pack(anchor=tk.W)
|
|
|
|
|
|
def mark_word_as_learned(self, word):
|
|
|
"""将单词标记为已学习"""
|
|
|
update_query = ("UPDATE words SET learned = 1 WHERE word = %s")
|
|
|
self.cursor.execute(update_query, (word,))
|
|
|
self.conn.commit()
|
|
|
|
|
|
|
|
|
class Window2(tk.Toplevel):
|
|
|
def __init__(self, master):
|
|
|
super().__init__(master)
|
|
|
self.title("单词拼写测试")
|
|
|
self.conn = pymysql.connect(
|
|
|
host="localhost",
|
|
|
user="root",
|
|
|
password="21412030117",
|
|
|
database="word",
|
|
|
charset='utf8mb4',
|
|
|
cursorclass=pymysql.cursors.DictCursor
|
|
|
)
|
|
|
self.cursor = self.conn.cursor()
|
|
|
self.setup_ui()
|
|
|
self.protocol("WM_DELETE_WINDOW", self.on_closing)
|
|
|
self.word_error_count = {} # 新增:存储单词错误次数的字典
|
|
|
|
|
|
def setup_ui(self):
|
|
|
self.word_label = tk.Label(self, text="", font=("Arial", 16))
|
|
|
self.word_label.pack(pady=10)
|
|
|
|
|
|
self.entry_var = tk.StringVar()
|
|
|
self.user_entry = tk.Entry(self, textvariable=self.entry_var, font=("Arial", 14))
|
|
|
self.user_entry.pack(ipady=5, pady=10)
|
|
|
|
|
|
self.result_label = tk.Label(self, text="", fg="black", font=("Arial", 12))
|
|
|
self.result_label.pack(pady=5)
|
|
|
|
|
|
self.next_button = tk.Button(self, text="下一个单词", state=tk.DISABLED, command=self.show_next_word)
|
|
|
self.next_button.pack(pady=10)
|
|
|
|
|
|
self.show_next_word() # 初始化显示一个单词
|
|
|
|
|
|
def show_next_word(self):
|
|
|
self.next_button.config(state=tk.DISABLED) # 禁用按钮防止重复点击
|
|
|
self.cursor.execute("SELECT `word`, `meaning` FROM `words` WHERE `learned` = 1 ORDER BY RAND() LIMIT 1")
|
|
|
word_row = self.cursor.fetchone()
|
|
|
if word_row:
|
|
|
self.current_word = word_row['word']
|
|
|
self.current_meaning = word_row['meaning']
|
|
|
self.word_label.config(text=f"含义:{self.current_meaning}")
|
|
|
self.entry_var.set("") # 清空输入框
|
|
|
self.result_label.config(text="")
|
|
|
self.user_entry.bind("<Return>", lambda event: self.check_spelling()) # 绑定回车键检查拼写
|
|
|
else:
|
|
|
messagebox.showinfo("提示", "没有更多已学习的单词可供测试!")
|
|
|
self.destroy()
|
|
|
|
|
|
def check_spelling(self):
|
|
|
user_input = self.entry_var.get().strip().lower()
|
|
|
if user_input == self.current_word.lower():
|
|
|
self.user_entry.config(fg="green") # 将输入框文字颜色设为绿色
|
|
|
self.result_label.config(text="正确!", fg="green")
|
|
|
self.next_button.config(state=tk.NORMAL) # 正确后启用按钮
|
|
|
self.word_error_count[self.current_word] = 0 # 重置错误计数
|
|
|
else:
|
|
|
self.result_label.config(text=f"错误!", fg="red")
|
|
|
self.user_entry.delete(0, tk.END) # 清空输入框并显示正确答案
|
|
|
self.user_entry.insert(0, self.current_word) # 在输入框中显示正确答案
|
|
|
self.user_entry.config(fg="red") # 将输入框文字颜色设为红色
|
|
|
self.user_entry.unbind("<Return>") # 避免在显示答案时响应回车键
|
|
|
self.user_entry.bind("<Button-1>", lambda event: self.clear_and_rebind(event)) # 绑定左键点击事件以清除并重新绑定
|
|
|
|
|
|
# 更新错误计数
|
|
|
if self.current_word in self.word_error_count:
|
|
|
self.word_error_count[self.current_word] += 1
|
|
|
else:
|
|
|
self.word_error_count[self.current_word] = 1
|
|
|
|
|
|
# 达到错误次数限制时更新数据库
|
|
|
if self.word_error_count[self.current_word] > 3:
|
|
|
self.update_easily_mistaken_in_db()
|
|
|
|
|
|
def update_easily_mistaken_in_db(self):
|
|
|
"""更新数据库中单词的easily_mistaken字段为1"""
|
|
|
try:
|
|
|
update_query = (
|
|
|
"UPDATE `words` SET `easily_mistaken` = 1 "
|
|
|
"WHERE `word` = %s AND `easily_mistaken` != 1"
|
|
|
)
|
|
|
self.cursor.execute(update_query, (self.current_word,))
|
|
|
self.conn.commit()
|
|
|
print(f"单词'{self.current_word}'标记为易错单词。")
|
|
|
except Exception as e:
|
|
|
print(f"更新数据库时出错:{e}")
|
|
|
def clear_and_rebind(self, event):
|
|
|
self.user_entry.delete(0, tk.END) # 清空输入框
|
|
|
self.user_entry.config(fg="black") # 重置输入框文字颜色为黑色
|
|
|
self.user_entry.bind("<Return>", lambda event: self.check_spelling()) # 重新绑定回车键事件
|
|
|
|
|
|
def on_closing(self):
|
|
|
self.conn.close()
|
|
|
self.destroy()
|
|
|
|
|
|
|
|
|
class Window3(tk.Toplevel):
|
|
|
def __init__(self, master):
|
|
|
super().__init__(master)
|
|
|
self.title("易错单词复习")
|
|
|
self.geometry("400x300")
|
|
|
|
|
|
# 初始化数据库连接
|
|
|
self.db = pymysql.connect(
|
|
|
host="localhost", # MySQL服务器地址
|
|
|
user="root", # 数据库用户名
|
|
|
password="21412030117", # 数据库密码
|
|
|
database="word", # 数据库名
|
|
|
charset='utf8mb4', # 字符编码,根据需要调整
|
|
|
cursorclass=pymysql.cursors.DictCursor # 使用字典游标,方便通过列名访问数据
|
|
|
)
|
|
|
self.cursor = self.db.cursor()
|
|
|
|
|
|
# 获取易错单词
|
|
|
self.fetch_mistaken_words()
|
|
|
|
|
|
# UI设置
|
|
|
self.word_label = tk.Label(self, text="", font=("Arial", 14))
|
|
|
self.word_label.pack(pady=20)
|
|
|
|
|
|
# 按钮
|
|
|
button_frame = tk.Frame(self)
|
|
|
button_frame.pack(pady=10)
|
|
|
tk.Button(button_frame, text="上一个单词", command=self.show_previous_word, state=tk.DISABLED).pack(
|
|
|
side=tk.LEFT, padx=10)
|
|
|
tk.Button(button_frame, text="下一个单词", command=self.show_next_word).pack(side=tk.RIGHT, padx=10)
|
|
|
|
|
|
# 初始化显示第一个单词
|
|
|
self.show_current_word()
|
|
|
|
|
|
def fetch_mistaken_words(self):
|
|
|
self.cursor.execute("SELECT `word`, `meaning` FROM `words` WHERE `easily_mistaken` = 1 ORDER BY `id`")
|
|
|
self.mistaken_words = self.cursor.fetchall()
|
|
|
self.current_index = 0
|
|
|
self.total_words = len(self.mistaken_words)
|
|
|
if self.total_words == 0:
|
|
|
messagebox.showinfo("提示", "没有易错单词可供复习!")
|
|
|
self.destroy()
|
|
|
|
|
|
def show_current_word(self):
|
|
|
if self.total_words > 0:
|
|
|
word_info = self.mistaken_words[self.current_index]
|
|
|
self.word_label.config(text=f"单词: {word_info['word']}, 意义: {word_info['meaning']}")
|
|
|
|
|
|
# 更新按钮状态
|
|
|
self.update_button_states()
|
|
|
|
|
|
def show_next_word(self):
|
|
|
if self.current_index < self.total_words - 1:
|
|
|
self.current_index += 1
|
|
|
else:
|
|
|
self.current_index = 0
|
|
|
self.show_current_word()
|
|
|
|
|
|
def show_previous_word(self):
|
|
|
if self.current_index > 0:
|
|
|
self.current_index -= 1
|
|
|
else:
|
|
|
self.current_index = self.total_words - 1
|
|
|
self.show_current_word()
|
|
|
|
|
|
def update_button_states(self):
|
|
|
if self.current_index == 0:
|
|
|
self.button_previous.configure(state=tk.DISABLED)
|
|
|
else:
|
|
|
self.button_previous.configure(state=tk.NORMAL)
|
|
|
if self.current_index == self.total_words - 1:
|
|
|
self.button_next.configure(state=tk.DISABLED)
|
|
|
else:
|
|
|
self.button_next.configure(state=tk.NORMAL)
|
|
|
|
|
|
def on_closing(self):
|
|
|
# 关闭窗口前的清理工作,如关闭数据库连接
|
|
|
self.db.close()
|
|
|
super().destroy()
|
|
|
|
|
|
# 实例化Window3的正确位置
|
|
|
if __name__ == "__main__":
|
|
|
root = tk.Tk()
|
|
|
root.withdraw() # 如果需要隐藏主窗口
|
|
|
window3 = Window3(root)
|
|
|
window3.protocol("WM_DELETE_WINDOW", window3.on_closing)
|
|
|
window3.mainloop()
|
|
|
|
|
|
|
|
|
def main():
|
|
|
# 初始化Tkinter的根窗口
|
|
|
root = tk.Tk()
|
|
|
root.withdraw() # 可选:隐藏根窗口,如果你不打算显示它的话
|
|
|
|
|
|
# 创建并显示Window3实例
|
|
|
window3 = Window3(root)
|
|
|
window3.protocol("WM_DELETE_WINDOW", window3.on_closing)
|
|
|
window3.mainloop() # 开始Window3窗口的事件循环
|
|
|
|
|
|
def start_application():
|
|
|
root = tk.Tk()
|
|
|
root.withdraw() # 隐藏根窗口,因为我们直接使用Toplevel作为登录界面
|
|
|
LoginPage(master=root) # 将主窗口作为master传给LoginPage,便于后续操作
|
|
|
root.mainloop() # 主循环在此启动,控制整个应用的生命周期
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
start_application() |