# -*- coding: utf-8 -*-
from tkinter import *
from tkinter import font
from tkinter import messagebox
from os import path
from os import remove
'''
单词记忆词典V1.0
'''
# 添加、编辑单词弹出框类
class PopupWindow(object):
# 初始化构造及添加组件到弹出框
def __init__(self, master, main_window, title, ciku=None):
self.main_window = main_window
top = self.top = Toplevel(master)
top.title(title)
top.resizable(False, False)
w = 280
h = 320
top.geometry('%dx%d+%d+%d' % (w, h, (ws - w) / 2, (hs - h) / 2))
top.bind('
m_font = font.Font(size=16)
l = Label(top, text="单词:", font=m_font)
l.pack(side=TOP, pady=5)
self.e1 = Entry(top)
self.e1.pack(side=TOP, padx=16, ipady=3, fill=X)
self.e1.focus()
if ciku is not None:
self.e1.insert(0, ciku.name)
l2 = Label(top, text="单词词性:", font=m_font)
l2.pack(side=TOP, pady=5)
self.e2 = Entry(top)
self.e2.pack(side=TOP, padx=16, ipady=3, fill=X)
if ciku is not None:
self.e2.insert(0, ciku.phone_number)
l2 = Label(top, text="解释:", font=m_font)
l2.pack(side=TOP, pady=5)
self.e3 = Entry(top)
self.e3.pack(side=TOP, padx=16, ipady=3, fill=X)
if ciku is not None:
self.e3.insert(0, ciku.work_place)
l2 = Label(top, text="备注:", font=m_font)
l2.pack(side=TOP, pady=5)
self.e4 = Entry(top)
self.e4.pack(side=TOP, padx=16, ipady=3, fill=X)
if ciku is not None:
self.e4.insert(0, ciku.e_mail)
if ciku is None:
b2 = Button(top, text='添加', width=12, command=lambda: self.add_click(None))
self.e4.bind('
else:
b2 = Button(top, text='编辑', width=12, command=lambda: self.edit_click(None))
self.e4.bind('
b2.pack(side=LEFT, pady=10, padx=20)
b3 = Button(top, text='取消', width=12, command=lambda: top.destroy())
b3.pack(side=RIGHT, pady=10, padx=20)
top.grab_set()
# 点击编辑单词按钮
def edit_click(self, event):
e1_name = self.e1.get()
if not e1_name:
messagebox.showinfo("出错了", '名字不能为空!')
return
e2_name = self.e2.get()
if not e2_name:
messagebox.showinfo("出错了", '单词词性不能为空!')
return
e3_name = self.e3.get()
e4_name = self.e4.get()
self.main_window.edit_value(e1_name, e2_name, e3_name, e4_name)
self.top.destroy()
# 点击添加单词按钮
def add_click(self, event):
e1_name = self.e1.get()
if not e1_name:
messagebox.showinfo("出错了", '名字不能为空!')
return
e2_name = self.e2.get()
if not e2_name:
messagebox.showinfo("出错了", '单词词性不能为空!')
return
e3_name = self.e3.get()
e4_name = self.e4.get()
self.main_window.add_value(e1_name, e2_name, e3_name, e4_name)
self.top.destroy()
# 主界面类
class MainWindow(object):
# 默认初始化构造
def __init__(self, root):
self.cikus = []
self.root = root
self.add_btn_widget()
self.add_search_widget()
self.add_listbox_widget()
self.add_statusbar_widget()
self.read_save_cikus()
self.sel_item = 0
# 添加操作按钮
def add_btn_widget(self):
frame = Frame(self.root)
frame.pack(pady=8)
self.addBtn = Button(frame, text='添加单词', width=15, command=lambda: self.popup("添加单词"))
self.addBtn.pack(padx=5, fill=X, side=LEFT)
self.delAllBtn = Button(frame, text='删除所有单词', width=15, command=self.del_all_cikus)
self.delAllBtn.pack(padx=5, fill=X, side=LEFT)
self.saveAllBtn = Button(frame, text='保存所有单词', width=15, command=self.save_all_cikus)
self.saveAllBtn.pack(padx=5, fill=X, side=LEFT)
# 添加搜索框
def add_search_widget(self):
frame = Frame(self.root)
frame.pack(pady=8)
entry1 = self.input_view = Entry(frame, width=34)
entry1.insert(0, '输入部分单词或单词词性按回车查询')
entry1.bind("
entry1.bind("
entry1.bind('
entry1.bind('
entry1.pack(ipady=3, padx=5, side=LEFT)
entry1.selection_range(0, len(entry1.get()))
entry1.focus()
command4 = self.search_btn = Button(frame, text='清空输入', width=15, command=lambda: self.cancel_search(None))
command4["state"] = "disabled"
command4.pack(padx=5, side=LEFT)
# 点击输入框清空内容
def click_input(self, event):
if self.input_view.get() == '输入部分单词或单词词性按回车查询':
self.input_view.delete(0, END)
# 输入框失去焦点时
def focusout_input(self, event):
if len(self.input_view.get()) == 0:
self.input_view.insert(0, '输入部分单词或单词词性按回车查询')
# 添加列表及滚动条
def add_listbox_widget(self):
frame = Frame(self.root)
frame.pack(pady=8)
bolded = font.Font(size=20)
self.lb = Listbox(frame, font=bolded, height=14, width=25, borderwidth=0)
scrollbar = Scrollbar(frame, orient=VERTICAL)
scrollbar.config(command=self.lb.yview)
scrollbar.pack(side=RIGHT, fill=Y)
self.lb.config(yscrollcommand=scrollbar.set, activestyle='none')
scrollbar2 = Scrollbar(frame, orient=HORIZONTAL)
scrollbar2.config(command=self.lb.xview)
scrollbar2.pack(side=BOTTOM, fill=X)
self.lb.config(xscrollcommand=scrollbar2.set, activestyle='none')
self.lb.pack(fill=BOTH)
self.lb.bind('
self.lb.bind('
# 添加界面底部单词数
def add_statusbar_widget(self):
frame = Frame(self.root)
frame.pack(pady=8, side=LEFT)
self.label = Label(frame, text='>词典现有 0 个单词<')
self.label.pack()
# 右键菜单
def rclick_popup(self, event):
a_menu = Menu(self.root, tearoff=0)
a_menu.add_command(label='编辑选中的单词', command=self.edit_ciku)
a_menu.add_command(label='删除选中的单词', command=self.del_ciku)
a_menu.post(event.x_root, event.y_root)
# 右键编辑选中的单词
def edit_ciku(self):
selection = self.lb.curselection()
if len(selection) == 0:
messagebox.showerror("出错了", '请先左键选中待操作的单词!')
return
self.sel_item = selection[0]
self.right_clidk_reset()
ciku = self.cikus[self.sel_item]
self.popup("编辑单词", ciku=ciku)
# 右键删除选中的单词
def del_ciku(self):
selection = self.lb.curselection()
if len(selection) == 0:
messagebox.showerror("出错了", '请先左键选中待操作的单词!')
return
self.right_clidk_reset()
answer = messagebox.askyesno("提示", "您确定要删除此单词吗?")
if answer:
self.lb.delete(self.sel_item, self.sel_item)
self.cikus.pop(self.sel_item)
self.label.config(text='词典现有 %d 个单词' % len(self.cikus))
messagebox.showinfo('提示', '单词从列表删除成功!\n若需要保存操作结果,请点击“保存所有单词”')
# 若是搜索后右键,则操作重置列表
def right_clidk_reset(self, is_dbclick=False):
b_text = self.search_btn["state"]
if b_text == "normal":
ic = -1
item = self.lb.selection_get()
if not is_dbclick:
self.cancel_search(None)
for ct in self.cikus:
ic += 1
if (ct.name in item) and (ct.phone_number in item):
break
self.sel_item = ic
self.lb.selection_set(ic, ic)
# 双击单词条目
def dbclick(self, event):
selection = self.lb.curselection()
self.sel_item = selection[0]
self.right_clidk_reset(is_dbclick=True)
ciku = self.cikus[self.sel_item]
wp = ciku.work_place if len(ciku.work_place) != 0 else '空'
em = ciku.e_mail if len(ciku.e_mail) != 0 else '空'
msg = '单词:%s\n词性:%s\n解释:%s\n备注:%s' % (ciku.name, ciku.phone_number, wp, em)
messagebox.showinfo("详细信息", msg)
# 添加、编辑单词弹窗
def popup(self, title, ciku=None):
self.cancel_search(None)
self.w = PopupWindow(self.root, self, title, ciku)
self.addBtn["state"] = "disabled"
self.root.wait_window(self.w.top)
self.addBtn["state"] = "normal"
# 删除所有单词
def del_all_cikus(self):
self.cancel_search(None)
answer = messagebox.askyesno("提示", "您确定要删除所有单词吗?")
if answer:
self.cikus.clear()
self.lb.delete(0, END)
remove("ciku.csv")
self.label.config(text='词典现有 %d 个单词' % len(self.cikus))
# 保存单词到文件
def save_all_cikus(self):
self.cancel_search(None)
f = open("ciku.csv", "w", encoding='gb2312')
for ciku in self.cikus:
str = '%s,%s,%s,%s\n' % (ciku.name, ciku.phone_number, ciku.work_place, ciku.e_mail)
f.write(str)
f.close()
messagebox.showinfo('提示', '保存 %d 个单词到文件成功!' % len(self.cikus))
# 读取保存在文件的单词
def read_save_cikus(self):
if not path.exists('ciku.csv'):
return
f = open("ciku.csv", "r", encoding='gb2312')
for line in f:
array = line.strip().split(',')
ciku = Ciku(array[0], array[1], array[2], array[3])
self.cikus.append(ciku)
self.lb.insert(END, '%s :%s' % (ciku.name, ciku.phone_number))
self.label.config(text='词典现有 %d 个单词' % len(self.cikus))
f.close()
# 添加单词回调
def add_value(self, name, phone_number, work_place, e_mail):
ciku = Ciku(name, phone_number, work_place, e_mail)
self.cikus.append(ciku)
self.lb.insert(END, '%s :%s' % (name, phone_number))
self.label.config(text='词典现有 %d 个单词' % len(self.cikus))
# 编辑联系回调
def edit_value(self, name, phone_number, work_place, e_mail):
ciku = self.cikus[self.sel_item]
ciku.name = name
ciku.phone_number = phone_number
ciku.work_place = work_place
ciku.e_mail = e_mail
self.lb.delete(0, END)
for ciku in self.cikus:
self.lb.insert(END, '%s :%s' % (ciku.name, ciku.phone_number))
self.label.config(text='词典现有 %d 个单词' % len(self.cikus))
# 搜索单词方法
def search_ciku(self, event):
self.search_btn["state"] = "normal"
self.lb.delete(0, END)
key = self.input_view.get().strip()
ci = 0
for ciku in self.cikus:
if (key in ciku.name) or (key in ciku.phone_number):
self.lb.insert(END, '%s :%s' % (ciku.name, ciku.phone_number))
ci += 1
self.label.config(text='查询到 %d 个单词' % ci)
# 取消搜索
def cancel_search(self, event):
b_state = self.search_btn["state"]
if b_state == "normal":
self.search_btn["state"] = "disabled"
self.lb.delete(0, END)
self.input_view.delete(0, END)
self.input_view.insert(0, '输入部分单词或单词词性按回车查询')
for ciku in self.cikus:
self.lb.insert(END, '%s :%s' % (ciku.name, ciku.phone_number))
self.label.config(text='词典现有 %d 个单词' % len(self.cikus))
self.input_view.selection_range(0, len(self.input_view.get()))
# 单词类对象
class Ciku:
def __init__(self, name, phone_number, work_place, e_mail):
self.name = name
self.phone_number = phone_number
self.work_place = work_place
self.e_mail = e_mail
# 程序启动入口
if __name__ == "__main__":
root = Tk()
root.wm_resizable(False, False)
root.title('单词记忆词典')
w = 380
h = 560
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
root.geometry('%dx%d+%d+%d' % (w, h, (ws - w) / 2, (hs - h) / 2))
m = MainWindow(root)
root.mainloop()