});

python 文本处理与tkinter入门

工作需要,得开发一些带GUI的小工具
在此记录下踩的坑

源码

使用

from ... import ...

是为了尽量减小打包后文件的大小
文中和

Canvas, PhotoImage, ico, bitmap

有关的语句也是为了减小打包后exe尺寸而注释掉的。

# import tkinter as tk
# from tkinter import Canvas, Label, StringVar, Entry, Button, Tk, PhotoImage, messagebox
from tkinter import Label, StringVar, Entry, Button, Tk, messagebox

# 窗口居中显示函数
def center_window(root, width, height):
  screenwidth = root.winfo_screenwidth()
  screenheight = root.winfo_screenheight()
  size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
  # print(size)
  root.geometry(size)
  root.update()
  # print(root.winfo_x())

# 创建窗口
window = Tk()
window.title('文本自动划分软件 2.0')
# window.geometry('500x200+1000+500') # 宽500, 高200,距左边1000,距上边500
center_window(window, 280, 200)
# ico_file = r'./TaiJi.ico'# 载入图标ico文件
# window.iconbitmap(bitmap=ico_file) # 设置窗口图标

###创建logo
##canvas = Canvas(window, height=150, width=150) # 创建画布
##img_file = PhotoImage(file=r'./Tai_Ji_Animation.gif') # 读取图片文件,只支持gif
##img = canvas.create_image(0,0, anchor='nw', image = img_file) # 放置图片于画布上, anchor后是按照方位表示的锚点位置
##canvas.pack(side='top') # 放置画布

# 创建标签
Label(window, text='文件名:').place(x=50, y= 50)
Label(window, text='(.txt)').place(x=200, y= 50)
note = '''说明:待转换文件和该程序
          需在同一文件中'''
Label(window, text=note).place(x=50, y= 80)

# 变量赋值
var_file_name = StringVar()
var_file_name.set('1000')
# 创建文件名输入示例
entry_file_name = Entry(window, textvariable=var_file_name, width=10)
entry_file_name.place(x=100, y=50)

# 文本转换代码(需要放在按钮前,以供按钮调用)
def text_convert():

  try:
    name = entry_file_name.get() # 读取entry框中的文本内容

    # open file readlines and save each line as a entity in data (type:list)
    with open(r'./'+name+'.txt', 'r') as f:
        data = f.readlines()

    # delete the row changing sign at the end of each row
    data = [i.strip('\n\t') for i in data]

    #  a new list to hold concated data
    smpl = []
    mod = len(data)//30 # the largest integer

    for i in range(mod):
        smpl.append('##'.join(data[i*30:i*30+29]))

    smpl.append('##'.join(data[mod*30:len(data)])) # put rest info to the last line

    smpl = ['======【第'+str(smpl.index(line)+1)+'行】======\n'+line+'\r' for line in smpl] # '\r\n' both stand for a new line

    with open(r'./'+name+'_30.txt','w') as f:
        f.writelines(smpl)

    messagebox.showinfo(title='Done', message='转换完成,共转换数据'+str(len(data))+'条\n结果文件名为'+name+'_30.txt')

  except FileNotFoundError: # 未找到文件时报错
    messagebox.showerror(title='Error', message='该文件夹中未找到'+name+'.txt\n')

# 运行按钮
btn_run = Button(window, text='开始转换', command=text_convert)#定义一个button按钮,名为开始转换,触发命令为text_convert
btn_run.place(x=110, y=120)

# 如果不加这条,打包后的exe窗口会闪退
window.mainloop()
print('sucessfully run')

参考网站:

感谢知识分享!

  1. 【tkinter大小位置自动调整-脚本之家】
  2. 【登录系统窗口教程系列2-莫烦python】

二次更新

增加csv对比模块
本来是用xlsx,但是pandas和openpyxl的打包一直无法成功,为此还自己写了CMD脚本
于是想到用csv,恰好python可以不借助其他包读写csv,因此快速试试。
亮点:

  1. 多次使用一行代码实现遍历处理,例如lambda函数的使用
  2. 利用index返回索引,读取csv中对应位置的信息
  3. try, except的丰富
top_y_2 = 140

Label(window, text='数据库:').place(x=50, y= top_y_2)
Label(window, text='(.txt)').place(x=200, y= top_y_2)
var_ref_name = StringVar()
var_ref_name.set('200')
entry_ref_name = Entry(window, textvariable=var_ref_name, width=10)
entry_ref_name.place(x=100, y=top_y_2)

Label(window, text='待对比:').place(x=50, y= top_y_2+30)
Label(window, text='(.csv)').place(x=200, y= top_y_2+30)
var_ln_name = StringVar()
var_ln_name.set('测试')
entry_ln_name = Entry(window, textvariable=var_ln_name, width=10)
entry_ln_name.place(x=100, y=top_y_2+30)

def examine():

  ref_name = entry_ref_name.get()
  ln_name = entry_ln_name.get()

  try:
    with open('./'+str(ref_name)+'.txt','r',encoding='utf-8') as f:
      refs = [ref.strip('\n') for ref in f.readlines()] # 逐行读取并消除首尾字符

    with open('./'+str(ln_name)+'.csv','r',encoding='utf-8') as f:
      lines = [line.strip('\n') for line in f.readlines()]

    # 读取各行逗号索引值
    # 截取微信号列,+1以跳过开头逗号
    idxes = [[i for i,s in enumerate(line) if s==','] for line in lines]
    numbers = [line[idx[0]+1:idx[1]] for idx, line in zip(idxes,lines)] 

    judge = lambda x:x if x in refs else '' # 单独定义比较函数
    sames = [judge(number) for number in numbers]
    sames[0] = '重复项' # 补个header

    outs = [line+same+',\n' for line,same in zip(lines, sames)]
    with open('./'+str(ln_name)+'_1'+'.csv','w',encoding='utf-8') as f:
        f.writelines(outs)

    messagebox.showinfo(title='Done', message=
                        '参考给出的'+str(len(refs))+'条数据\n'
                        +'本次筛选的'+str(len(lines)-lines.count(''))+'条的数据中\n'
                        +'包含重复数据'+str(len(sames)-sames.count(''))+'条\n'
                        +'处理结果保存至“'+str(ln_name)+'_1'+'.csv”中')

  except FileNotFoundError:
    messagebox.showerror(title='Error', message='该文件夹中未找到“'+ref_name+'.txt”\n'+'或“'+ln_name+'.csv”')

  except Exception as e:
    messagebox.showerror(title='Error', message='错误类型:“'+str(e)+'”\n错误日志已自动保存至该文件夹“error_log.txt”中\n请联系开发者并发送该报告')
    with open('./error_log'+'.txt','w',encoding='utf-8') as f:
        f.writelines(str(e))

# 运行按钮
btn_run = Button(window, text='开始筛选', command=examine)
btn_run.place(x=110, y=top_y_2+60)

写的两个bat批处理文件:

  1. pyinstaller自动安装
    call activate text_3.6
    D:
    cd XYX\TMP\XiongXi\0731_Data
    pyinstaller -F -w TC-4.0.1.py -i hd.ico
    pause
    exit
  2. 运行并记录日志
    D:
    cd XYX\TMP\XiongXi\0731_Data\dist
    TC_2.exe>log.txt 2>&1
    pause
    exit
  3. 自动创建环境并安装所需库
    这里尝试3.6和3.8是因为看到github讨论中说pyinstaller对3.7的支持兼容不好

    conda create python=3.6 -n text_3.6 pandas pyinstaller -y
    conda create python=3.8 -n text_3.8 pandas pyinstaller -y

其他

pyinstaller打包图标不变,可能由于explore.exe有缓存,或是由于ico对应不同尺寸的图标
如果无需担心两个集合内部的顺序,可以用【set】,考虑顺序,还是建议上述方法。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.