通过前面学习的 Tkinter 知识,这一节我们将《垃圾邮件识别器》所需要的界面搭建起来,界面主要包括:
- 主窗口
- 顶部菜单
- 中心文本框
- 底部状态栏
1. 主窗口
创建 MainFrame.py 文件,创建 MainFrame 类如下:
import tkinter as tk class MainFrame(tk.Tk): def __init__(self): # 初始化父类 super(MainFrame, self).__init__() # 定义窗口宽高 self.window_w, self.window_h = 800, 500 # 获得屏幕尺寸 screen_w, screen_h = self.winfo_screenwidth(), self.winfo_screenheight() # 计算窗口屏幕中心位置 start_x, start_y = int(screen_w / 2 - self.window_w / 2), int(screen_h / 2 - self.window_h / 2) # 设置屏幕尺寸以及初始位置 self.geometry(f'{self.window_w}x{self.window_h}+{start_x}+{start_y}') # 设置窗口标题 self.title('垃圾邮件识别器') # 初始化其他窗口 self.init_widgets() def init_widgets(self): pass def show(self): self.mainloop()
创建程序入口文件 App.py,其中代码如下:
from MainFrame import MainFrame if __name__ == '__main__': main_frame = MainFrame() main_frame.show()
2. 菜单类
创建一个 TopMenu.py 并在该文件中编写如下代码:
import sys import tkinter as tk from tkinter.filedialog import askopenfilenames import codecs import time import hashlib class TopMenu(tk.Menu): def __init__(self, predict_function): super(TopMenu, self).__init__() # 菜单回调 self.predict_function = predict_function # 创建菜单 self.file_menu() self.mail_menu() self.help_menu() # 添加文件菜单 def file_menu(self): file_menu = tk.Menu(master=self, tearoff=False) file_menu.add_command(label='打开') file_menu.add_separator() file_menu.add_command(label='退出', command=sys.exit) self.add_cascade(label='文件', menu=file_menu) # 添加邮件菜单 def mail_menu(self): mail_menu = tk.Menu(master=self, tearoff=False) mail_menu.add_command(label='识别', command=self.predict_function) self.add_cascade(label='邮件', menu=mail_menu) # 添加关于我菜单 def help_menu(self): about_menu = tk.Menu(master=self, tearoff=False) about_menu.add_command(label='关于') self.add_cascade(label='帮助', menu=about_menu) if __name__ == '__main__': window = tk.Tk() window.geometry('800x500+300+300') menu = TopMenu(predict_function=lambda : print('Hello World')) window.config(menu=menu) window.mainloop()
3. 中心文本框
创建 CenterText.py 文件,并在该文件中编写如下代码:
import tkinter as tk from tkinter.scrolledtext import ScrolledText import hashlib from datetime import datetime class CenText(tk.PanedWindow): INPUT_NULL = -1 INPUT_SAME = -2 def __init__(self): super(CenText, self).__init__() self.config(orient=tk.HORIZONTAL) self.widgetName = 'CenText' self.init_widgets() def init_widgets(self): # 窗口属性 config = {'bd': 0, 'highlightthickness': 0, 'wrap': tk.NONE} # 输入文本框 self.mail_area = ScrolledText(**config) # 信息提示框 self.info_area = tk.Text(**config) self.set_info_disable() # 定义字体样式 self.info_area.tag_configure("custom", font=("宋体", 10, "bold"), foreground="red") self.info_area.tag_configure("normal", font=("宋体", 10, "bold"), foreground="black") # 添加文本框 self.add(self.mail_area) self.add(self.info_area) # 邮件哈希值 self.prev_hexdigest = '' def set_info_disable(self): """使得信息显示框不可输入""" self.info_area.config(state='disabled') def set_info_normal(self): """使得信息显示框可输入""" self.info_area.config(state='normal') def add_info(self, text, font='normal'): """信息框添加格式化的信息""" self.set_info_normal() # 获得当前时间 cur_time = datetime.now() cur_time = cur_time.strftime("%Y/%m/%d %H:%M:%S") self.info_area.insert(tk.END, f'{cur_time} {text}\n', font) self.set_info_disable() # 滚动条移动到最后 self.info_area.yview_moveto(1.0) def get_mail(self): """获得邮件输入框内容""" mail = self.mail_area.get("1.0", tk.END).strip() if len(mail) == 0: return CenText.INPUT_NULL # 计算文本哈希摘要 hash = hashlib.sha256() hash.update(mail.encode()) curr_hexdigest = hash.hexdigest() # 判断文本是否变化 if curr_hexdigest == self.prev_hexdigest: return CenText.INPUT_SAME self.prev_hexdigest = curr_hexdigest return mail if __name__ == '__main__': window = tk.Tk() window.geometry('800x500+300+300') text = CenText() text.pack(fill=tk.BOTH, expand=True) button1 = tk.Button(text='添加文本', command=lambda: text.add_info('这是测试文本', font='custom')) button1.pack(side=tk.BOTTOM) button2 = tk.Button(text='获得文本', command=lambda: print(text.get_mail())) button2.pack(side=tk.BOTTOM) window.mainloop()
4. 状态栏
创建 StatusBar.py 文件,并编写如下代码:
import random import tkinter as tk class StatBar(tk.Frame): def __init__(self): super(StatBar, self).__init__() # 设置控件属性 self.config(borderwidth=0, bg='#bdc3c7') # 初始化子控件 self.init_widgets() def init_widgets(self): self.message = tk.Label(self, text=" 准备就绪", bg='#bdc3c7') self.message.pack(side=tk.LEFT) def set_message(self, text): self.message['text'] = text if __name__ == '__main__': window = tk.Tk() window.geometry('800x500+300+300') sbar = StatBar() sbar.pack(side=tk.BOTTOM, fill=tk.X) btn1 = tk.Button(text='改变状态栏文字', command=lambda: sbar.set_message(f'状态文字修改:{random.randint(0, 100)}')) btn1.pack(side=tk.TOP) window.mainloop()
5. 整合控件到主窗口
将头部菜单、中心文本框、底部状态栏创建到主窗口 MainFrame 中,如下:
import tkinter as tk class MainFrame(tk.Tk): .... def init_widgets(self): from TopMenu import TopMenu from StatBar import StatBar from CenText import CenText # 初始化头部菜单 self.menu = TopMenu(predict_function=self.on_menu_predict) self.config(menu=self.menu) # 初始化中心文本框 self.text = CenText() self.text.pack(fill=tk.BOTH, expand=True) # 初始化底部状态栏 self.sbar = StatBar() self.sbar.pack(side=tk.BOTTOM, fill=tk.X) def on_menu_predict(self): print('预测邮件') ...