主題: 002.02 Tkinter圖形介面之文字範例
建檔日期: 2019/08/26
更新日期: None
語言: Python 3.7.4, tkinter 8.6
系統: Win10 Ver. 10.0.17763 繁體中文版(TW)
002.02 Tkinter圖形介面之文字範例
範例以tkinter建立程式, 供使用者建立文字檔案, 在過程中記錄下使用者輸入中文字的關連性, 隨後提供中文輸入協助的快捷鍵, 對輸入比較的人可以起到有效的協助. 主要用到的部件有Tk(), Frame(), Button(), Label()以及Text(), 還有按鍵及滑鼠事件處理; 另外還有檔案對話filedialog及訊息框messagebox的使用.
程式介面
'''
使用Tkinter的Text部件, 建立一個簡單的文字編輯器, 主要的功能為:
[1] 系統會按使用者輸的中文字, 記錄下使用者輸入的第二個中文字的使用情形, 下次
再輸入這個字, 會提供前十二個最常使用的下一個字, 供使用者以F1~F12按鍵直接輸入.
[2] 使用者可以讀入以前的文字檔案, 直接學習, 建立自己的字典
[3] 這個輔助輸入的字典, 是專為個人使用, 不是一般通用的字典, 一般來說, 個人常用
的詞彙大都在幾百字, 對輸入較慢的人, 可以起到很大的作用.
'''
from tkinter.filedialog import *
from tkinter import *
from tkinter import messagebox
def enter(event): # 滑鼠進入物件, 背景改為黑色
event.widget.config(bg='black')
def leave(event): # 滑鼠離間物件, 背景改為原背景色
event.widget.config(bg=gnd)
def open_new_file():
'''
開啟文字檔案, 格式以utf-8, utf-16, GB18030來讀取
'''
# 開啟檔案對話方塊
filename = filedialog.askopenfilename(title = "選擇檔案",
filetypes = (("文字檔案","*.txt"),("所有檔案","*.*")))
new_text = None
# 開啟檔案, 試以utf-8, utf-16及GB18030來開啟, 無法開啟則顥示錯誤
if filename != "":
print(filename)
try:
print('utf-8')
new_f = open(filename, 'rt', encoding = 'utf-8')
new_text = new_f.read()
except UnicodeDecodeError as e:
try:
print('utf-8 Failed')
new_f = open(filename, 'rt', encoding = 'utf-16')
new_text = new_f.read()
except UnicodeDecodeError as e:
try:
print('utf-16 Failed')
new_f = open(filename, 'rt', encoding = 'GB18030')
new_text = new_f.read()
except UnicodeDecodeError as e:
print('GB18030 Failed')
pass
# 檔案讀入, 顯示在TEXT部件中
if new_text != None:
print(new_f)
print(new_text)
main_widget.t1.delete('1.0', END)
main_widget.t1.insert(END, new_text)
main_widget.t1.edit_modified(False)
else:
messagebox.showinfo(title='檔案開啟錯誤', message='文字檔案格式無法讀取或檔案有問題')
def save_new_file():
# 開啟存檔對話方塊
filename = filedialog.asksaveasfilename(title = "儲存檔案",
filetypes = (("文字檔案","*.txt"),("所有檔案","*.*")))
if filename != "":
if filename[-4:].lower() != '.txt':
filename = filename + '.txt'
new_f = open(filename, 'wt', encoding = decoder)
new_f.write(main_widget.t1.get('1.0',END))
new_f.close()
def end_job():
# 字典存檔, 下次可再使用
if dictionary != {}:
datafile = open(dictionary_file, 'wt', encoding=decoder)
datafile.write(str(dictionary))
datafile.close()
root.destroy()
exit()
def learn_dictionary():
# 讀入的檔案內容, 分析內容, 加入字典中
txt = main_widget.t1.get('1.0',END)
for i in range(len(txt))[1:]:
pre_char = txt[i-1]
new_char = txt[i]
add_dictionary(pre_char, new_char)
def cmd(i):
# 按鈕處理程式
if i == 0: # 開啟檔案
if main_widget.t1.edit_modified():
answer = messagebox.askquestion ('開啟檔案',
'內容已修改, 是否捨棄, 另開新檔 ?',icon = 'warning')
if answer == 'yes':
open_new_file()
else:
open_new_file()
elif i == 1: # 存入檔案
save_new_file()
elif i == 2: # 學習本文中的內容
learn_dictionary()
elif i == 3: # 結束離開
if main_widget.t1.edit_modified():
answer = messagebox.askquestion ('離開編輯',
'內容已修改, 是否捨棄離開 ?',icon = 'warning')
if answer == 'yes':
end_job()
else:
end_job()
def new_button(f, string, column, row):
# 建立功能按鈕
obj = Button(f, text=string, font=font, width=len(string)*2, height=1, bg=gnd,
fg='white', bd=0, activebackground=gnd, command = lambda i = column: cmd(i))
obj.bind('<Enter>', enter)
obj.bind('<Leave>', leave)
obj.pack(side=LEFT)
return obj
def new_label(f, string, column, row):
# 建立F1~F12的標籤
obj = Label(f, text=string, font=font, width=len(string), height=1, bg=gnd,
fg=l_gnd, bd=0, activebackground=gnd)
obj.pack(side=LEFT)
return obj
def read_dictionary():
# 讀入已有的字典, 格式為{}空字典, {'字':{'字':次數, ....}, ....}
dic_f = open(dictionary_file, 'rt', encoding = decoder)
a = dic_f.read()
dictionary = eval(a)
dic_f.close()
return dictionary
def write_dictionary():
# 字典寫入檔案
dic_f = open(dictionary_file, 'wt', encoding = decoder)
dic_f.write(str(dictionary))
return dictionary
def find_char(char):
# 取該字的下一個最常用字清單, 共十二個, 沒有補全格空格
char_dic = dictionary[char].items()
rev_list = [[v[1], v[0]] for v in char_dic]
rev_list.sort(reverse=True)
word_list = [v[1] for v in rev_list]
if len(word_list)<12:
for i in range(12-len(word_list)):
word_list.append(' ')
else:
word_list = word_list[:12]
return word_list
def find_key(char):
# 取得對應的常用字列表, 不在字典中, 則給十二個全格空格
if char not in dictionary:
word_list = [' ' for i in range(12)]
else:
word_list = find_char(char)
return word_list
def update_char(char):
# 顯示十二個常用字的內容
word_list = find_key(char)
for i in range(len(key_list)):
main_widget.key[i].config(text=word_list[i])
def add_dictionary(pre_char, new_char):
'''
檢查是不是中文字 ?
是中文字, 前一個字也是中文字的話
是新字, 則加入字典
不是新字, 該字的次數加1
'''
if '\u4e00' <= pre_char <= '\u9fa5':
if '\u4e00' <= new_char <= '\u9fa5':
if pre_char in dictionary:
if new_char in dictionary[pre_char]:
dictionary[pre_char][new_char] += 1
else:
dictionary[pre_char][new_char] = 1
else:
dictionary[pre_char] = {new_char:1}
def key_action(event):
if 112<=event.keycode<=123: # 檢查是不是F1~F12按鍵
insert_char = main_widget.key[event.keycode-112]['text']
if insert_char != ' ':
main_widget.t1.insert(INSERT,insert_char)
update_char(insert_char)
else: # 按輸入字, F1~F12內容更新
char = event.widget.get("%s-1c" % INSERT, INSERT)
update_char(char)
# 檢查前一字, 與現在的字, 字典更新處理
pre_char = event.widget.get("%s-2c" % INSERT, "%s-1c" % INSERT)
new_char = event.widget.get("%s-1c" % INSERT, INSERT)
add_dictionary(pre_char, new_char)
class main_window():
'''
主視窗建立顯示
Frame1放四個功能鍵(save, write, analysis, exit)
Frame2放十二個標籤(F1 ~ F12)
Frame3放一個文字再加一個垂直滾動條
'''
def __init__(self):
menu_b = []
self.f_all = Frame(root, bg=gnd, padx=pad, pady=pad)
self.f_all.pack()
self.f1 = Frame(self.f_all, bg=gnd)
self.f1.pack(side=TOP)
for i in range(len(menu)):
menu_b.append(new_button(self.f1, menu[i], i, 0))
self.f2 = Frame(self.f_all, bg=gnd)
self.f2.pack(side=TOP)
self.key=[]
for i in range(len(key_list)):
new_label(self.f2, key_list[i], i*2, 1)
self.key.append(new_button(self.f2, word_list[i], i*2, 1))
self.f3 = Frame(self.f_all, bg=gnd)
self.f3.pack(side=TOP)
self.t1 = Text(self.f3, font=font, fg='white', bg=l_gnd, width=80,
height=20, padx=pad, pady=pad)
self.t1.pack(side=LEFT, fill=Y)
self.s1 = Scrollbar(self.f3)
self.s1.pack(side=RIGHT, fill=Y)
self.s1.config(command=self.t1.yview)
self.t1.config(yscrollcommand=self.s1.set)
# 按鍵放開處理
self.t1.bind('<KeyRelease>', key_action)
font_size = 20
font = ('微軟黑體', font_size, 'bold')
pad = 10
gnd = 'gray20'
l_gnd = 'gray40'
title = '輔助輸入編輯器 V1.0'
decoder = "utf-8-sig"
key_list = ["F1 ","F2 ","F3 ","F4 ","F5 ","F6 ", "F7 ","F8 ","F9 ","F10","F11","F12"]
dictionary_file = 'dictionary.txt' # 字典檔名
menu = ('開啟檔案', '儲存檔案', '學習內容', '離開編輯')
dictionary = read_dictionary() # 讀入字典
word_list = [" " for i in range(12)] # F1 ~ F12 空白內容
root = Tk()
root.title(title)
root.resizable(False, False)
main_widget = main_window() # 建立程式視窗內容
root.mainloop()
# dictionary.txt 新檔自建內容為空字典 {}
# dictionary.txt 已有的內容示範
{'中': {'文': 2, '有': 2, '運': 2, '一': 1, '避': 1, '誕': 1, '類': 1, '繁': 1, '的': 5, '出': 3, '所': 1, '集': 1, '討': 1, '和': 1}, '文': {'維': 1, '件': 11, '本': 9, '獻': 3, '單': 1, '檔': 1, '語': 1, '化': 1, '字': 1}, '維': {'基': 27, '圖': 1, '護': 3}, '基': {'百': 8, '金': 6, '數': 3, '教': 4, '於': 14, '本': 2, '共': 3, '語': 2, '學': 2, '社': 1, '媒': 3}, '百': {'科': 9, '上': 1}, '科': {'條': 1, '全': 1, '書': 5, '學': 9, '技': 1, '的': 1, '標': 1, '免': 1}, '條': {'目': 4, '件': 4, '款': 3}, '目': {'協': 1, '錄': 2, '的': 4, '標': 1, '討': 1, '中': 1}, '協': {'作': 1, '調': 1, '議': 5, '程': 1}, '作': {'計': 1, '系': 7, '為': 11, '簡': 1, '者': 1, '變': 1, '業': 2, '用': 2, '的': 1, '是': 2, '對': 1, '配': 1}, '計': {'劃': 4, '者': 1, '哲': 4, '算': 16, '的': 9, '工': 1, '任': 1, '為': 1, '師': 1, '目': 1, '時': 1, '允': 1, '有': 1, '社': 1, '框': 1, '主': 1}, '劃': {'專': 1, '分': 1, '例': 1, '線': 6, '中': 1}, '專': {'頁': 1, '門': 4, '業': 1}, '頁': {'已': 1, '設': 2, '技': 1, '面': 4}, '已': {'建': 1, '在': 1, '決': 1, '時': 1, '經': 7, '無': 1, '正': 1}, .......... }