123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- import tktool
- import tkinter
- import tkinter.ttk as ttk
- import tkinter.filedialog as fd
- import tkinter.messagebox as msg
- from typing import List, Tuple, Callable, Optional
- import abc
- import db
- import word
- class HEnglishTkinter(tktool.TkEventMain, metaclass=abc.ABCMeta):
- tk_zoom = 1
- def set_after_run(self, ms, func, *args): # 正常运行前设置定时任务 super.__init__可能会调用
- self.init_after_run_list.append((ms, func, args))
- def __conf_set_after_run(self): # 配合 set_after_run 使用
- for ms, func, args in self.init_after_run_list:
- self.set_after_run_now(ms, func, *args)
- def set_after_run_now(self, ms, func, *args): # 正常运行时设置定时任务
- self._window.after(ms, func, *args)
- def __init__(self, title: str,
- top: Optional["HEnglishTkinter"] = None,
- size: Tuple[float, float] = ((1 / 3), (2 / 3))):
- self.init_after_run_list: List[Tuple[int, Callable, Tuple]] = []
- super(HEnglishTkinter, self).__init__()
- if top:
- self._window = tkinter.Toplevel(top._window)
- top._window.lift()
- else:
- self._window = tkinter.Tk()
- self._sys_height = self._window.winfo_screenheight()
- self._sys_width = self._window.winfo_screenwidth()
- self._win_height = int(self._sys_height * size[1] * self.tk_zoom) # 窗口高度
- self._win_width = int(self._sys_width * size[0] * self.tk_zoom) # 窗口宽度
- self.__conf_windows(title)
- self.__conf_set_after_run()
- def __conf_windows(self, title: str):
- self._window.title(title)
- self._window.geometry(f'{self._win_width}x{self._win_height}')
- self._window['bg'] = '#F0FFFF'
- self._window.resizable(True, True) # 禁止缩放
- self._window.overrideredirect(False) # 显示标题栏
- self._window.bind('<Configure>', self.__window_resize) # 调整界面大小
- self._window.minsize(int(self._sys_width * (1 / 3) * self.tk_zoom),
- int(self._sys_height * (1 / 3) * self.tk_zoom))
- self._create_windows()
- self._set_windows()
- def __window_resize(self, event=None):
- if self._win_width != self._window.winfo_width() or self._win_height != self._window.winfo_height():
- self._win_height = self._window.winfo_height()
- self._win_width = self._window.winfo_width()
- self._set_windows()
- @abc.abstractmethod
- def _create_windows(self):
- pass
- @abc.abstractmethod
- def _set_windows(self):
- pass
- def mainloop(self):
- self._window.mainloop()
- class HEnglish(HEnglishTkinter):
- def __init__(self):
- super(HEnglish, self).__init__("H-English")
- self.db = db.WordDatabase()
- self.wd = self.db.wd
- def _create_windows(self):
- self._title_label = tkinter.Label(self._window)
- self._control_frame = tkinter.Frame(self._window)
- self._control_btn = [tkinter.Button(self._control_frame) for _ in range(6)]
- def _set_windows(self):
- self.__conf_title()
- self.__conf_control_btn()
- def __conf_title(self):
- if self._win_width >= self._win_height:
- font = tktool.make_font(size=int(self._win_height * 0.06), weight="bold")
- else:
- font = tktool.make_font(size=int(self._win_width * 0.05), weight="bold")
- self._title_label['font'] = font
- self._title_label['bg'] = '#F0FFFF'
- self._title_label['text'] = "Huan-English-Dictionary" # 使用英语标题在GUI更美观
- self._title_label['anchor'] = 'c'
- self._title_label.place(relx=0.0, rely=0.03, relwidth=1.0, relheight=0.13)
- self._title = tkinter.Label()
- def __conf_control_btn(self):
- if self._win_width >= self._win_height:
- font = tktool.make_font(size=int(self._win_height * 0.03))
- self._control_btn[0].place(relx=0.07, rely=0.10, relwidth=0.4, relheight=0.2)
- self._control_btn[1].place(relx=0.53, rely=0.10, relwidth=0.4, relheight=0.2)
- self._control_btn[2].place(relx=0.07, rely=0.40, relwidth=0.4, relheight=0.2)
- self._control_btn[3].place(relx=0.53, rely=0.40, relwidth=0.4, relheight=0.2)
- self._control_btn[4].place(relx=0.07, rely=0.70, relwidth=0.4, relheight=0.2)
- self._control_btn[5].place(relx=0.53, rely=0.70, relwidth=0.4, relheight=0.2)
- else:
- font = tktool.make_font(size=int(self._win_width * 0.03))
- self._control_btn[0].place(relx=0.1, rely=0.08, relwidth=0.8, relheight=0.1)
- self._control_btn[1].place(relx=0.1, rely=0.23, relwidth=0.8, relheight=0.1)
- self._control_btn[2].place(relx=0.1, rely=0.38, relwidth=0.8, relheight=0.1)
- self._control_btn[3].place(relx=0.1, rely=0.53, relwidth=0.8, relheight=0.1)
- self._control_btn[4].place(relx=0.1, rely=0.68, relwidth=0.8, relheight=0.1)
- self._control_btn[5].place(relx=0.1, rely=0.83, relwidth=0.8, relheight=0.1)
- self._control_frame['bg'] = "#FFFFFF"
- self._control_frame['relief'] = "ridge"
- self._control_frame['bd'] = 5
- self._control_frame.place(relx=0.05, rely=0.20, relwidth=0.90, relheight=0.75)
- for i in zip(self._control_btn,
- ["Word Test", "Dictionary", "Export", "Import", "Delete", "About"],
- ["#DCDCDC", "#DCDCDC", "#DCDCDC", "#DCDCDC", "#DCDCDC", "#DCDCDC"],
- [None, None, None, self.import_word, None, None]):
- i[0]['font'] = font
- i[0]['fg'] = "#000000"
- i[0]['bg'] = i[2]
- i[0]['activeforeground'] = "#FFFFFF"
- i[0]['activebackground'] = i[2]
- i[0]['anchor'] = 'c'
- i[0]['relief'] = "ridge"
- i[0]['bd'] = 5
- i[0]['text'] = i[1]
- i[0]['command'] = i[3]
- def import_word(self):
- Import(self, self._window)
- def show_loading(self, title: str): # 有子线程时显示加载
- ...
- def stop_loading(self): # 子线程运行完成后关闭加载
- ...
- def disable(self):
- self._window.state('icon')
- for i in self._control_btn:
- i['state'] = 'disable'
- def enable(self):
- self._window.state('normal')
- for i in self._control_btn:
- i['state'] = 'normal'
- class Import(HEnglishTkinter):
- class ImportEvent(tktool.TkEventBase, metaclass=abc.ABCMeta):
- def __init__(self, imp: "Import"):
- super().__init__()
- self.imp = imp
- self.thread = None
- self.file = ""
- @abc.abstractmethod
- def func(self, *args):
- ...
- def get_title(self) -> str:
- return "Import"
- def start(self, *args):
- self.thread = tktool.TkThreading(self.func, *args)
- return self
- def done_after_event(self):
- res = self.thread.wait_event()
- if res:
- msg.showinfo("操作成功", f"成功从{self.file}中读取单词")
- class ImportFromText(ImportEvent):
- def __init__(self, imp: "Import"):
- super().__init__(imp)
- def func(self, file: str):
- self.file = file
- return self.imp._father.db.update_from_txt(file)
- class ImportFromTable(ImportEvent):
- def __init__(self, imp: "Import"):
- super().__init__(imp)
- def func(self, file: str, t: str):
- self.file = file
- return self.imp._father.db.update_from_table(file, t)
- def __init__(self, father: HEnglish, father_windows: tkinter.Tk):
- super(Import, self).__init__("Import", father, size=(1 / 3, 1 / 3))
- self._father = father
- self._father_windows = father_windows
- self._father.disable()
- self._window.protocol("WM_DELETE_WINDOW", self.close)
- def close(self):
- self._window.destroy()
- self._father.enable()
- def _create_windows(self):
- self._title_label = tkinter.Label(self._window)
- self._loading_pro = ttk.Progressbar(self._window)
- self._control_btn = [tkinter.Button(self._window) for _ in range(6)]
- def _set_windows(self):
- self.__conf_title()
- self.__conf_loader()
- self.__conf_control_btn()
- def __conf_title(self):
- if self._win_width >= self._win_height:
- font = tktool.make_font(size=int(self._win_height * 0.06), weight="bold")
- else:
- font = tktool.make_font(size=int(self._win_width * 0.05), weight="bold")
- self._title_label['font'] = font
- self._title_label['bg'] = '#F0FFFF'
- self._title_label['text'] = "Import Word" # 使用英语标题在GUI更美观
- self._title_label['anchor'] = 'c'
- self._title_label.place(relx=0.0, rely=0.03, relwidth=1.0, relheight=0.13)
- self._title = tkinter.Label()
- def __conf_loader(self):
- self._loading_pro['mode'] = 'indeterminate' # 来回显示
- self._loading_pro['orient'] = 'horizontal' # 横向进度条
- self._loading_pro['maximum'] = 100
- def __conf_control_btn(self):
- if self._win_width >= self._win_height:
- font = tktool.make_font(size=int(self._win_height * 0.04))
- self._control_btn[0].place(relx=0.07, rely=0.28, relwidth=0.4, relheight=0.2)
- self._control_btn[1].place(relx=0.53, rely=0.28, relwidth=0.4, relheight=0.2)
- self._control_btn[2].place(relx=0.07, rely=0.66, relwidth=0.4, relheight=0.2)
- self._control_btn[3].place(relx=0.53, rely=0.66, relwidth=0.4, relheight=0.2)
- else:
- font = tktool.make_font(size=int(self._win_width * 0.04))
- self._control_btn[0].place(relx=0.1, rely=0.20, relwidth=0.8, relheight=0.1)
- self._control_btn[1].place(relx=0.1, rely=0.33, relwidth=0.8, relheight=0.1)
- self._control_btn[2].place(relx=0.1, rely=0.46, relwidth=0.8, relheight=0.1)
- self._control_btn[3].place(relx=0.1, rely=0.59, relwidth=0.8, relheight=0.1)
- for i in zip(self._control_btn,
- ["From Text", "From CSV", "From Excel", "From Json"],
- ["#DCDCDC", "#DCDCDC", "#DCDCDC", "#DCDCDC"],
- [self.import_from_text, self.import_from_csv, self.import_from_excel, self.import_from_json]):
- i[0]['font'] = font
- i[0]['fg'] = "#000000"
- i[0]['bg'] = i[2]
- i[0]['activeforeground'] = "#FFFFFF"
- i[0]['activebackground'] = i[2]
- i[0]['anchor'] = 'c'
- i[0]['relief'] = "ridge"
- i[0]['bd'] = 5
- i[0]['text'] = i[1]
- i[0]['command'] = i[3]
- def import_from_text(self):
- file = fd.askopenfilename(filetypes=[("Text", ".txt"), ("All", "*")])
- if file != "":
- self.push_event(self.ImportFromText(self).start(file))
- def import_from_csv(self):
- file = fd.askopenfilename(filetypes=[("CSV", ".csv"), ("All", "*")])
- if file != "":
- self.push_event(self.ImportFromTable(self).start(file, "csv"))
- def import_from_excel(self):
- file = fd.askopenfilename(filetypes=[("Excel", ".xlsx"), ("All", "*")])
- if file != "":
- self.push_event(self.ImportFromTable(self).start(file, "excel"))
- def import_from_json(self):
- file = fd.askopenfilename(filetypes=[("Json", ".json"), ("All", "*")])
- if file != "":
- self.push_event(self.ImportFromTable(self).start(file, "json"))
- def show_loading(self, title: str):
- self._loading_pro['value'] = 0
- self._loading_pro.place(relx=0.10, rely=0.17, relwidth=0.80, relheight=0.05)
- self._loading_pro.start(50)
- def stop_loading(self):
- self._loading_pro.place_forget()
- self._loading_pro.stop()
- if __name__ == '__main__':
- hgui = HEnglish()
- hgui.mainloop()
|