更新: 2017.07.17 補(bǔ)充滾動(dòng)條,、win批處理拉起py 2017.08.13 新增自定義圖標(biāo)
--------原創(chuàng) blogs: http://www.cnblogs.com/chenyuebai --------
一,、背景: 1.工作中自己及同事在查數(shù)據(jù)庫(kù)、測(cè)試接口時(shí)需要對(duì)一些字符串或json串作預(yù)處理,,目前這些問題網(wǎng)上均有在線轉(zhuǎn)換的工具,,但很繁雜,可能需要打開幾個(gè)網(wǎng)頁(yè)窗口,; 2.之前給妹子做的文本處理工具(http://www.cnblogs.com/chenyuebai/p/6999561.html)是基于cmd命令行的,,不太友好; 3.自己做的一些小工具也基本都是命令行執(zhí)行的,,也想接觸下GUI,;
基于以上,了解到python自帶的tkinter庫(kù)可以初步滿足UI的需求,,業(yè)余時(shí)間做了個(gè)圖形化工具,,涉及窗口、文本,、按鈕,、標(biāo)簽、菜單,、菜單樹,、滾動(dòng)條、文件處理,、界面布局等,; 下文將梳理從零到完成的全過程,作為自己GUI學(xué)習(xí)的一個(gè)總結(jié),; ps:后面版本間隙有時(shí)間的話想試試用pyQt來做,。。tkinter做出的界面確實(shí),。,。。23333 工具界面截圖:
二,、實(shí)現(xiàn) 1.安裝所需要的庫(kù) ps:環(huán)境是win7+python 3.6,,tkinter是py的標(biāo)準(zhǔn)庫(kù),即:如不涉及EXCEL處理,,可跳過此步驟,;使用python處理Excel表格,后面有時(shí)間會(huì)單獨(dú)整理 (1)et-xmlfile openpyxl安裝需要依賴,,工具里有涉及處理EXCEL(xlsx),需要用到openpyxl庫(kù),; (2)jdcal 同上 (3)openpyxl 處理EXCEL(xlsx) (4)xlrd 讀取EXCEL(xls) (5)xlwt 寫入EXCEL(xls) (6)xltils 配合上面兩個(gè)庫(kù)對(duì)已存在表格進(jìn)行修改 2.新建父窗口(可理解為界面的最底層) ################################################################# #author: 陳月白 #_blogs: http://www.cnblogs.com/chenyuebai/ ################################################################# from tkinter import * def gui_start(): init_window = Tk() #實(shí)例化出一個(gè)父窗口 init_window.mainloop() #父窗口進(jìn)入事件循環(huán),,可以理解為保持窗口運(yùn)行,,否則界面不展示 gui_start() 運(yùn)行結(jié)果:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 運(yùn)行會(huì)彈出上圖所示的空白窗口,這里我們還可以修改窗口默認(rèn)大小,、默認(rèn)彈出位置,、窗口名、父窗口顏色,、虛化等等,; init_window.title("文本處理工具 by: 陳月白") init_window.geometry('290x160+10+10') #290 160為窗口大小,+10 +10 定義窗口彈出時(shí)的默認(rèn)展示位置 init_window["bg"] = "pink" #窗口背景色,,其他背景色見:blog.csdn.net/chl0000/article/details/7657887 init_window.attributes("-alpha",0.8) #虛化 值越小虛化程度越高 注意要加在 init_window.mainloop() 之前,; 運(yùn)行結(jié)果:
整理下代碼: ################################################################# #author: 陳月白 #_blogs: http://www.cnblogs.com/chenyuebai/ ################################################################# from tkinter import *
先到這,,有時(shí)間再整理。,。 --------------------------------------------------------------------------------
下面以“字符串轉(zhuǎn)MD5”為例,,介紹數(shù)據(jù)讀取,、按鈕、布局,、事件觸發(fā),、后臺(tái)轉(zhuǎn)換處理、界面展示結(jié)果,; (1)標(biāo)簽 self.init_data_label = Label(self.init_window_name, text="待處理數(shù)據(jù)") self.init_data_label.grid(row=0, column=0) self.result_data_label = Label(self.init_window_name, text="輸出結(jié)果") self.result_data_label.grid(row=0, column=12) 這里正好提一下grid(),,說下我的理解,。grid()方法是tkinter庫(kù)自帶的布局函數(shù),他可以將父窗口分割成類似一個(gè)Excel表格,,對(duì)單個(gè)組件按照參數(shù)中傳遞的row,、column放置在指定位置,,并展示; 下圖紅框部分,,代表整個(gè)父窗口界面: 代碼中的:self.init_data_label.grid(row=0, column=0) 代表將“init_data_label”這個(gè)標(biāo)簽放置在頁(yè)面的第一行,,第一列的位置(即左上角),并展示,;
(2)文本框 self.init_data_Text = Text(self.init_window_name, width=67, height=35) #原始數(shù)據(jù)錄入框 self.init_data_Text.grid(row=1, column=0, rowspan=10, columnspan=10) self.result_data_Text = Text(self.init_window_name, width=70, height=49) #處理結(jié)果展示 self.result_data_Text.grid(row=1, column=12, rowspan=15, columnspan=10) self.init_data_Text.grid(row=1, column=0, rowspan=10, columnspan=10) #"rowspan=10" 是grid()方法的一個(gè)參數(shù),,用于指定該組件(init_data_Text)占用的行數(shù),,同理columnspan用于指定占用列數(shù);
(3)按鈕 按鈕的創(chuàng)建可以使用Button()方法實(shí)現(xiàn),,可自定義按鈕大小,,寬度,按鈕文本,,背景色,,以及需要觸發(fā)的事件; #按鈕 self.str_trans_to_md5_button = Button(self.init_window_name, text="字符串轉(zhuǎn)MD5", bg="lightblue", width=10,command=self.str_trans_to_md5) # 調(diào)用內(nèi)部方法 加()為直接調(diào)用 self.str_trans_to_md5_button.grid(row=1, column=11) 觸發(fā)事件:在定義按鈕時(shí),,使用command=functionname這個(gè)參數(shù)來指定,;當(dāng)按鈕被點(diǎn)擊,就會(huì)調(diào)用command后的方法,,從而完成事件的觸發(fā),; 這里有個(gè)小坑。,。,。就是command后跟函數(shù)名時(shí),不可加括號(hào),,否則在代碼執(zhí)行時(shí),,就會(huì)觸發(fā)該函數(shù); 舉個(gè)例子,,上面貼的代碼中“command=self.str_trans_to_md5”若寫為“command=self.str_trans_to_md5()”,,該gui_test.py在執(zhí)行時(shí)便會(huì)調(diào)用類中的self.str_trans_to_md5()方法,而不是在點(diǎn)擊按鈕時(shí)才觸發(fā),;
(4)事件代碼:后臺(tái)的處理 step3中在定義按鈕時(shí),,會(huì)選擇觸發(fā)一個(gè)事件(或稱為函數(shù)),,函數(shù)的實(shí)現(xiàn)涉及:從界面文本框中讀取待處理數(shù)據(jù)---邏輯處理---界面結(jié)果文本框展示 code: def str_trans_to_md5(self): src = self.init_data_Text.get(1.0,END).strip().replace("\n","").encode() #print("src =",src) if src: try: myMd5 = hashlib.md5() myMd5.update(src) myMd5_Digest = myMd5.hexdigest() #print(myMd5_Digest) #輸出到界面 self.result_data_Text.delete(1.0,END) self.result_data_Text.insert(1.0,myMd5_Digest) #從第一行開始 except: self.result_data_Text.delete(1.0,END) self.result_data_Text.insert(1.0,"字符串轉(zhuǎn)MD5失敗") else: print("ERROR") #界面左下角會(huì)有日志框,支持動(dòng)態(tài)打印,,下面會(huì)提到 讀取待處理數(shù)據(jù):對(duì)之前定義的self.init_data_Text(待處理數(shù)據(jù)文本框)可使用tkinter庫(kù)中自帶的get()方法,獲取文本框中的內(nèi)容,,str類型,; 邏輯處理:MD5加密,不展開了,,從網(wǎng)上找的例子照著敲,; 界面結(jié)果文本框展示:對(duì)獲取的字符串處理后,即可使用Text.insert(index,strdata)方法插入結(jié)果文本框:self.result_data_Text,; 插入前建議先清理下,,Text.delete(1.0,END)代表將文本框從第一行刪除至最后一行,即清空,;
(5)日志打印 和上面沒啥區(qū)別,,直接貼代碼了~ def get_current_time(self): current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) return current_time #日志動(dòng)態(tài)打印 def write_log_to_Text(self,logmsg): global LOG_LINE_NUM current_time = self.get_current_time() logmsg_in = str(current_time) +" " + str(logmsg) + "\n" #換行 if LOG_LINE_NUM <= 7: self.log_data_Text.insert(END, logmsg_in) LOG_LINE_NUM = LOG_LINE_NUM + 1 else: self.log_data_Text.delete(1.0,2.0) self.log_data_Text.insert(END, logmsg_in) #移動(dòng)光標(biāo) self.log_data_Text.focus_force()
整體的例子代碼如下: ################################################################# #author: 陳月白 #_blogs: http://www.cnblogs.com/chenyuebai/ ################################################################# from tkinter import * import hashlib import time LOG_LINE_NUM = 0 class MY_GUI(): def __init__(self,init_window_name): self.init_window_name = init_window_name #設(shè)置窗口 def set_init_window(self): self.init_window_name.title("文本處理工具_(dá)v1.2 by: 陳月白") #窗口名 #self.init_window_name.geometry('320x160+10+10') #290 160為窗口大小,+10 +10 定義窗口彈出時(shí)的默認(rèn)展示位置 self.init_window_name.geometry('1068x681+10+10') #self.init_window_name["bg"] = "pink" #窗口背景色,,其他背景色見:blog.csdn.net/chl0000/article/details/7657887 #self.init_window_name.attributes("-alpha",0.9) #虛化,,值越小虛化程度越高 #標(biāo)簽 self.init_data_label = Label(self.init_window_name, text="待處理數(shù)據(jù)") self.init_data_label.grid(row=0, column=0) self.result_data_label = Label(self.init_window_name, text="輸出結(jié)果") self.result_data_label.grid(row=0, column=12) self.log_label = Label(self.init_window_name, text="日志") self.log_label.grid(row=12, column=0) #文本框 self.init_data_Text = Text(self.init_window_name, width=67, height=35) #原始數(shù)據(jù)錄入框 self.init_data_Text.grid(row=1, column=0, rowspan=10, columnspan=10) self.result_data_Text = Text(self.init_window_name, width=70, height=49) #處理結(jié)果展示 self.result_data_Text.grid(row=1, column=12, rowspan=15, columnspan=10) self.log_data_Text = Text(self.init_window_name, width=66, height=9) # 日志框 self.log_data_Text.grid(row=13, column=0, columnspan=10) #按鈕 self.str_trans_to_md5_button = Button(self.init_window_name, text="字符串轉(zhuǎn)MD5", bg="lightblue", width=10,command=self.str_trans_to_md5) # 調(diào)用內(nèi)部方法 加()為直接調(diào)用 self.str_trans_to_md5_button.grid(row=1, column=11) #功能函數(shù) def str_trans_to_md5(self): src = self.init_data_Text.get(1.0,END).strip().replace("\n","").encode() #print("src =",src) if src: try: myMd5 = hashlib.md5() myMd5.update(src) myMd5_Digest = myMd5.hexdigest() #print(myMd5_Digest) #輸出到界面 self.result_data_Text.delete(1.0,END) self.result_data_Text.insert(1.0,myMd5_Digest) self.write_log_to_Text("INFO:str_trans_to_md5 success") except: self.result_data_Text.delete(1.0,END) self.result_data_Text.insert(1.0,"字符串轉(zhuǎn)MD5失敗") else: self.write_log_to_Text("ERROR:str_trans_to_md5 failed") #獲取當(dāng)前時(shí)間 def get_current_time(self): current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) return current_time #日志動(dòng)態(tài)打印 def write_log_to_Text(self,logmsg): global LOG_LINE_NUM current_time = self.get_current_time() logmsg_in = str(current_time) +" " + str(logmsg) + "\n" #換行 if LOG_LINE_NUM <= 7: self.log_data_Text.insert(END, logmsg_in) LOG_LINE_NUM = LOG_LINE_NUM + 1 else: self.log_data_Text.delete(1.0,2.0) self.log_data_Text.insert(END, logmsg_in) def gui_start(): init_window = Tk() #實(shí)例化出一個(gè)父窗口 ZMJ_PORTAL = MY_GUI(init_window) # 設(shè)置根窗口默認(rèn)屬性 ZMJ_PORTAL.set_init_window() init_window.mainloop() #父窗口進(jìn)入事件循環(huán),可以理解為保持窗口運(yùn)行,,否則界面不展示 gui_start()
上面例子代碼的執(zhí)行結(jié)果:
大概就是這些,,其他功能、按鈕大同小異,,就不贅述了,; 有問題歡迎留言交流; 后面有時(shí)間會(huì)補(bǔ)充用windows批處理拉起python代碼,,這樣就可以像普通軟件一樣使用這個(gè)小工具了,;
2017.07.14
--------------------------------------------------------------------------------
(6)滾動(dòng)條 對(duì)于展示長(zhǎng)文本,,需要在Text文本框側(cè)翼(或下方)提供滾動(dòng)條,;tkinter庫(kù)中提供Scrollbar()方法創(chuàng)建一個(gè)滾動(dòng)條 # 滾動(dòng)條 self.result_data_scrollbar_y = Scrollbar(self.init_window_name) #創(chuàng)建縱向滾動(dòng)條 self.result_data_scrollbar_y.config(command=self.result_data_Text.yview) #將創(chuàng)建的滾動(dòng)條通過command參數(shù)綁定到需要拖動(dòng)的Text上 self.result_data_Text.config(yscrollcommand=self.result_data_scrollbar_y.set) #Text反向綁定滾動(dòng)條 self.result_data_scrollbar_y.grid(row=1, column=23, rowspan=15, sticky='NS') ps1:滾動(dòng)條與待綁定的組件(Text或其他)時(shí),需要二者相互綁定,,從而達(dá)到拖動(dòng)任意一方,,對(duì)應(yīng)方同步移動(dòng); ps2:grid()中rowspan的值最好取Text文本框的值,,可以使?jié)L動(dòng)條長(zhǎng)度完美貼合文本框 效果:
三,、其他 1.windows批處理拉起python py代碼完成后,為方便使用,,可以使用windows批處理腳本拉起python代碼 common_tools_gui.py所在目錄下新建start.bat,,寫入 @python common_tools_gui.py %* @pause @pause可以保持代碼一直處于運(yùn)行狀態(tài),,而不是控制臺(tái)一閃而過; #python需配置在環(huán)境變量中,,或者使用絕對(duì)路徑,。。 但也會(huì)帶來一個(gè)問題,,就是在雙擊這個(gè)批處理時(shí),,軟件界面出來的同時(shí),會(huì)附帶一個(gè)黑色的cmd控制臺(tái)窗口,;
百度了一下,,可以使用windows的.vbs拉起批處理來規(guī)避: common_tools_gui.py所在目錄下新建start_my_gui.vbs,寫入 Set ws = CreateObject("Wscript.Shell") 此時(shí)雙擊該vbs腳本,,即可拉起軟件界面,,且隱藏cmd控制臺(tái)界面;
2. 暫時(shí)木有了,。,。 后面項(xiàng)目間隙有可能會(huì)研究下robotFramework~ 也有可能會(huì)試著用pyQt重寫下這個(gè)界面 先到這了;
2017.07.17 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3.自定義圖標(biāo) python打開工具時(shí),,左上角默認(rèn)為tkinter默認(rèn)圖標(biāo),,任務(wù)欄為python默認(rèn)圖標(biāo); 查了下,,python的tkinter庫(kù)支持自定義圖標(biāo):py文件當(dāng)前目錄下制作ico圖標(biāo)文件(https://www./),,父窗口使用iconbitmap()方法,指定該文件即可,; self.init_window_name.iconbitmap('text_processing_tools.ico') #指定界面圖標(biāo) 中途有個(gè)坑,,就是僅左上角生效,但windows下方的任務(wù)欄無效,; 百度之,,大概意思是文本工具的py文件運(yùn)行時(shí),windows認(rèn)為彈出的工具窗口是python解釋器的衍生程序(子程序,?),,即默認(rèn)仍使用pythpn解釋器的圖標(biāo); 需要在代碼中指定彈出窗口的AppUserModelID即可: import ctypes 效果: 左上角: 底側(cè)任務(wù)欄:
附目錄結(jié)構(gòu):
2017.08.13
|
|