python3.6 +tkinter GUI编程 实现界面化的文本处理工具
更新:
2017.07.17 补充滚动条、win批处理拉起py
2017.08.13 新增自定义图标
--------原创 blogs: http://www.cnblogs.com/chenyuebai --------
一、背景:
1.工作中自己及同事在查数据库、测试接口时需要对一些字符串或json串作预处理,目前这些问题网上均有在线转换的工具,但很繁杂,可能需要打开几个网页窗口;
2.之前给妹子做的文本处理工具(http://www.cnblogs.com/chenyuebai/p/6999561.html)是基于cmd命令行的,不太友好;
3.自己做的一些小工具也基本都是命令行执行的,也想接触下GUI;
基于以上,了解到python自带的tkinter库可以初步满足UI的需求,业余时间做了个图形化工具,涉及窗口、文本、按钮、标签、菜单、菜单树、滚动条、文件处理、界面布局等;
下文将梳理从零到完成的全过程,作为自己GUI学习的一个总结;
ps:后面版本间隙有时间的话想试试用pyQt来做。。tkinter做出的界面确实。。。23333
工具界面截图:
二、实现
1.安装所需要的库 ps:环境是win7+python 3.6,tkinter是py的标准库,即:如不涉及EXCEL处理,可跳过此步骤;使用python处理Excel表格,后面有时间会单独整理
(1)et-xmlfile openpyxl安装需要依赖,工具里有涉及处理EXCEL(xlsx),需要用到openpyxl库;
(2)jdcal 同上
(3)openpyxl 处理EXCEL(xlsx)
(4)xlrd 读取EXCEL(xls)
(5)xlwt 写入EXCEL(xls)
(6)xltils 配合上面两个库对已存在表格进行修改
2.新建父窗口(可理解为界面的最底层)
#################################################################
#author: 陈月白
#_blogs: http://www.cnblogs.com/chenyuebai/
#################################################################
from tkinter import * def gui_start():
init_window = Tk() #实例化出一个父窗口
init_window.mainloop() #父窗口进入事件循环,可以理解为保持窗口运行,否则界面不展示 gui_start()
运行结果:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
运行会弹出上图所示的空白窗口,这里我们还可以修改窗口默认大小、默认弹出位置、窗口名、父窗口颜色、虚化等等;
init_window.title("文本处理工具 by: 陈月白")
init_window.geometry('290x160+10+10') #290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置
init_window["bg"] = "pink" #窗口背景色,其他背景色见:blog.csdn.net/chl0000/article/details/7657887
init_window.attributes("-alpha",0.8) #虚化 值越小虚化程度越高
注意要加在 init_window.mainloop() 之前;
运行结果:
整理下代码:
#################################################################
#author: 陈月白
#_blogs: http://www.cnblogs.com/chenyuebai/
#################################################################
from tkinter import *
import hashlib
class MY_GUI():
def __init__(self,init_window_name):
self.init_window_name = init_window_name #设置窗口
def set_init_window(self):
self.init_window_name.title("文本处理工具_v1.2 by: 陈月白") #窗口名
self.init_window_name.geometry('1068x680+10+10') #290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置
self.init_window_name["bg"] = "pink" #窗口背景色,其他背景色见:blog.csdn.net/chl0000/article/details/7657887
self.init_window_name.attributes("-alpha",0.9) #虚化,值越小虚化程度越高 def gui_start():
init_window = Tk() #实例化出一个父窗口
ZMJ_PORTAL = MY_GUI(init_window)
# 设置根窗口默认属性
ZMJ_PORTAL.set_init_window() init_window.mainloop() #父窗口进入事件循环,可以理解为保持窗口运行,否则界面不展示 gui_start()
先到这,有时间再整理。。
--------------------------------------------------------------------------------
继续。
3.父窗口完成后,即可基于父窗口创建其他组件
下面以“字符串转MD5”为例,介绍数据读取、按钮、布局、事件触发、后台转换处理、界面展示结果;
(1)标签
标签可以使用tkinter里的Label()方法,生成标签,括号内可带入其他属性参数;
生成标签后需使用grid()或者pack()方法使其展示; #注:tkinter对于同一个父窗口,只可允许使用一种布局函数;另外还有个place()方法,不过目前我还没用过;
self.init_data_label = Label(self.init_window_name, text="待处理数据")
self.init_data_label.grid(row=0, column=0)
self.result_data_label = Label(self.init_window_name, text="输出结果")
self.result_data_label.grid(row=0, column=12)
这里正好提一下grid(),说下我的理解。grid()方法是tkinter库自带的布局函数,他可以将父窗口分割成类似一个Excel表格,对单个组件按照参数中传递的row、column放置在指定位置,并展示;
下图红框部分,代表整个父窗口界面:
代码中的:self.init_data_label.grid(row=0, column=0) 代表将“init_data_label”这个标签放置在页面的第一行,第一列的位置(即左上角),并展示;
(2)文本框
tkinter库中的Text()方法,可以创建一个文本框,用于数据的录入和结果展示;Text()方法可以传入其他参数值,用于定义如背景颜色,前景色,字体,字号、字色等
self.init_data_Text = Text(self.init_window_name, width=67, height=35) #原始数据录入框
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) #处理结果展示
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()方法的一个参数,用于指定该组件(init_data_Text)占用的行数,同理columnspan用于指定占用列数;
(3)按钮
按钮的创建可以使用Button()方法实现,可自定义按钮大小,宽度,按钮文本,背景色,以及需要触发的事件;
#按钮
self.str_trans_to_md5_button = Button(self.init_window_name, text="字符串转MD5", bg="lightblue", width=10,command=self.str_trans_to_md5) # 调用内部方法 加()为直接调用
self.str_trans_to_md5_button.grid(row=1, column=11)
触发事件:在定义按钮时,使用command=functionname这个参数来指定;当按钮被点击,就会调用command后的方法,从而完成事件的触发;
这里有个小坑。。。就是command后跟函数名时,不可加括号,否则在代码执行时,就会触发该函数;
举个例子,上面贴的代码中“command=self.str_trans_to_md5”若写为“command=self.str_trans_to_md5()”,该gui_test.py在执行时便会调用类中的self.str_trans_to_md5()方法,而不是在点击按钮时才触发;
(4)事件代码:后台的处理
step3中在定义按钮时,会选择触发一个事件(或称为函数),函数的实现涉及:从界面文本框中读取待处理数据---逻辑处理---界面结果文本框展示
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,"字符串转MD5失败")
else:
print("ERROR") #界面左下角会有日志框,支持动态打印,下面会提到
读取待处理数据:对之前定义的self.init_data_Text(待处理数据文本框)可使用tkinter库中自带的get()方法,获取文本框中的内容,str类型;
逻辑处理:MD5加密,不展开了,从网上找的例子照着敲;
界面结果文本框展示:对获取的字符串处理后,即可使用Text.insert(index,strdata)方法插入结果文本框:self.result_data_Text;
插入前建议先清理下,Text.delete(1.0,END)代表将文本框从第一行删除至最后一行,即清空;
(5)日志打印
和上面没啥区别,直接贴代码了~
def get_current_time(self):
current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
return current_time #日志动态打印
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)
#移动光标
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 #设置窗口
def set_init_window(self):
self.init_window_name.title("文本处理工具_v1.2 by: 陈月白") #窗口名
#self.init_window_name.geometry('320x160+10+10') #290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置
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) #虚化,值越小虚化程度越高
#标签
self.init_data_label = Label(self.init_window_name, text="待处理数据")
self.init_data_label.grid(row=0, column=0)
self.result_data_label = Label(self.init_window_name, text="输出结果")
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) #原始数据录入框
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) #处理结果展示
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="字符串转MD5", bg="lightblue", width=10,command=self.str_trans_to_md5) # 调用内部方法 加()为直接调用
self.str_trans_to_md5_button.grid(row=1, column=11) #功能函数
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,"字符串转MD5失败")
else:
self.write_log_to_Text("ERROR:str_trans_to_md5 failed") #获取当前时间
def get_current_time(self):
current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
return current_time #日志动态打印
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() #实例化出一个父窗口
ZMJ_PORTAL = MY_GUI(init_window)
# 设置根窗口默认属性
ZMJ_PORTAL.set_init_window() init_window.mainloop() #父窗口进入事件循环,可以理解为保持窗口运行,否则界面不展示 gui_start()
上面例子代码的执行结果:
大概就是这些,其他功能、按钮大同小异,就不赘述了;
有问题欢迎留言交流;
后面有时间会补充用windows批处理拉起python代码,这样就可以像普通软件一样使用这个小工具了;
2017.07.14
--------------------------------------------------------------------------------
继续。
(6)滚动条
对于展示长文本,需要在Text文本框侧翼(或下方)提供滚动条;tkinter库中提供Scrollbar()方法创建一个滚动条
# 滚动条
self.result_data_scrollbar_y = Scrollbar(self.init_window_name) #创建纵向滚动条
self.result_data_scrollbar_y.config(command=self.result_data_Text.yview) #将创建的滚动条通过command参数绑定到需要拖动的Text上
self.result_data_Text.config(yscrollcommand=self.result_data_scrollbar_y.set) #Text反向绑定滚动条
self.result_data_scrollbar_y.grid(row=1, column=23, rowspan=15, sticky='NS')
ps1:滚动条与待绑定的组件(Text或其他)时,需要二者相互绑定,从而达到拖动任意一方,对应方同步移动;
ps2:grid()中rowspan的值最好取Text文本框的值,可以使滚动条长度完美贴合文本框
效果:
三、其他
1.windows批处理拉起python
py代码完成后,为方便使用,可以使用windows批处理脚本拉起python代码
common_tools_gui.py所在目录下新建start.bat,写入 @python common_tools_gui.py %* @pause
@pause可以保持代码一直处于运行状态,而不是控制台一闪而过; #python需配置在环境变量中,或者使用绝对路径。。
但也会带来一个问题,就是在双击这个批处理时,软件界面出来的同时,会附带一个黑色的cmd控制台窗口;
百度了一下,可以使用windows的.vbs拉起批处理来规避:
common_tools_gui.py所在目录下新建start_my_gui.vbs,写入
Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c start.bat",vbhide
此时双击该vbs脚本,即可拉起软件界面,且隐藏cmd控制台界面;
2. 暂时木有了。。
后面项目间隙有可能会研究下robotFramework~
也有可能会试着用pyQt重写下这个界面
先到这了;
2017.07.17
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3.自定义图标
python打开工具时,左上角默认为tkinter默认图标,任务栏为python默认图标;
查了下,python的tkinter库支持自定义图标:py文件当前目录下制作ico图标文件(https://www.ico.la/),父窗口使用iconbitmap()方法,指定该文件即可;
self.init_window_name.iconbitmap('text_processing_tools.ico') #指定界面图标
中途有个坑,就是仅左上角生效,但windows下方的任务栏无效;
百度之,大概意思是文本工具的py文件运行时,windows认为弹出的工具窗口是python解释器的衍生程序(子程序?),即默认仍使用pythpn解释器的图标;
需要在代码中指定弹出窗口的AppUserModelID即可:
import ctypes
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")
效果:
左上角: 底侧任务栏:
附目录结构:
2017.08.13
python3.6 +tkinter GUI编程 实现界面化的文本处理工具的更多相关文章
- tkinter GUI编程
tkinter编程概述 tkinter模块包含在Python的基本安装包中.使用tkinter模块编写的GUI程序是跨平台的.可在windows.UNIX.Linux以及Macintonsh OS X ...
- python 打开文件对话框 filedialog tkinter GUI 编程
- -读取文件的gui编程 # _*_ coding:utf-8 _*_ import tkinter from tkinter import filedialog def openfiles2(): ...
- 2018-09-28 用Python3和tkinter开发简单图形界面程序
源码库: program-in-chinese/wubi_code_editor 起因在这里. 由于此项目和汉字相关, 个人也想尝试Python的图形界面开发, 于是开始尝试. 遇到的一个坑. 用户测 ...
- Java之GUI编程
GUI编程 组建 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 1.简介 GUI的核心技术:Swing AWT 为什么不流行? 界面不美观. 需要jre环境.(没必 ...
- 第34天学习打卡(GUI编程之组件和容器 frame panel 布局管理 事件监听 多个按钮共享一个事件 )
GUI编程 组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 1 简介 GUi的核心技术:Swing AWT 1.界面不美观 2.需要jre环境 为什么要学习GU ...
- Python GUI编程(Tkinter) windows界面开发
Python实现GUI简单的来说可以调用Tkinter库,这样一般的需求都可以实现,显示简单的windows窗口代码如下: python_gui.py 1 #!C:\Python27\python.e ...
- GUI编程(Tkinter) 笔记分享
Python GUI编程(Tkinter) Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的 ...
- Python之GUI编程(Tkinter))
不足之处,还请海涵,请指出不足.本人发布过的文章,会不断更改,力求减少错误信息. 一.重要放在开头:模块 如出现这种错误 ModuleNotFoundError: No module named 'n ...
- python大法好——ython GUI编程(Tkinter)
Python GUI编程(Tkinter) Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的 ...
随机推荐
- Holding Bin-Laden Captive!(1.多重背包 2.母函数)
Holding Bin-Laden Captive! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/ ...
- CentOs7相对于CentOs6的常用命令变化
比如说防火墙在CentOS6中为 iptables,在CentOS7中变为 firewalld. service iptables stop/start/restart systemctl stop/ ...
- 玩玩Qt(一)
最近在看一些关于游戏引擎的东西,本来是有几个游戏的小点子,其实实现起来还挺麻烦的,想找个游戏引擎看看能不能码起来.辗转之后发现了很多2D引擎,其中国产的要数cocos2dx用的好像是比较广泛,但是好多 ...
- font-size:100% 原因
The browser default which is something like 16pt for Firefox, You can check by going into Firefox op ...
- WPF TextBox按字节长度限制输入
前两天做一个项目的时候,由于页面没有限制TextBox的输入长度,所以,后台直接报错了,超出数据库最大的长度. 数据库的长度是按照字节来计算的,而且不同的编码格式,汉字占用的字节长度又不相同,比如,我 ...
- HTML5网页音乐播放器
1功能介绍 HTML5中推出了音视频标签,可以让我们不借助其他插件就可以直接播放音视频.下面我们就利用H5的audio标签及其相关属性和方法来制作一个简单的音乐播放器.主要包括以下几个功能: 1.播放 ...
- Java Enum用法详解
Java Enum用法详解 用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举 ...
- C#截取当前活动窗体的图片
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- javascript正则多次调用test 结果交替出现
现在需要一个正则验证小数点后保留一到三位数,小数点前只能两位或一位整数的这么一个数. 正则如: var reg = /^\d{,}\.\d{,}$/g; 验证如下: 因为我们用1.23符合规则的数据去 ...
- Spring4 AOP详解
Spring4 AOP详解 第一章Spring 快速入门并没有对Spring4 的 AOP 做太多的描述,是因为AOP切面编程概念不好理解.所以这章主要从三个方面详解AOP:AOP简介(了解),基于注 ...