使用PyQt5自制文件查找工具,并生成EXE文件

一、工作中,有一个关键词查找工作,查找开发版本中使用的文本,有哪些词语是非法的,一个一个去查太累了,所以想到了用代码来实现。可后来想想,能否做成简单的小工具,大家都可以使用。

于是就着手编写工具。原来是计划用Python自带的lib库:tkinter,写的时候发现真不好操作,网上对应的说明文档也比较少。所以查找了好久,决定用PyQt5来实现。

二、大概思路:①.使用designer.exe绘制窗体;②使用eric6生成主窗口对应的py文件;③编辑调用主窗口的程序;④使用信号(signal)和槽(slot)机制建立窗体的动作指令;⑤调试打包

三、实现过程

1.PyQt5的安装上篇已做介绍,打开designer.exe,新建一个ui文件。如图,放置了3个QPushButton,然后放置了QLineEdit和QTextEdit,第一个设置了默认文本(placeholderText设置),保存为openfile.ui

 使用PyQt5自制文件查找工具,并生成EXE文件

2.在eric6中,先创建一个项目,在forms窗体,添加openfile.ui,然后编译,生成Ui_openfile.py,如下附录2中的代码

3.创建主程序openfile.py,导入界面程序:from Ui_openfile import *,然后再导入其他需要的库。

4.编写类class,定义其中关于界面点击的函数

 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。方法:类中定义的函数。

5.定义方法:findtxt,主要实现查找已有文本,是否在目标文件中。方法findtxt是一个槽函数,要与前面的信号关联起来。所以在前面的Ui_openfile.py,添加信号语句:self.button_find.clicked.connect(self.findtxt),这样信号和槽就关联起来了。

在获取目标文件时,需要打开一个文件选择框。此时定义了另一个函数:loadtxt,实现打开文件选择控件,获取文本内容,并把目标文件的路径写在下方的文本框里。使用方法:self.loadtxt()来调用类中的另一个函数,获取目标文件内容。

(另外:方法loadtxt也可以成为一个槽函数,要与前面的信号关联起来。可以在前面的Ui_openfile.py,添加信号语句:self.button_openfile.clicked.connect(self.loadtxt),进行信号和槽的关联)

当查找完毕后,可以在findtxt后面添加语句: self.lineEdit.setText('结果已保存在D盘list.txt文件')。这样就可以做到通知执行结果的作用。

6.同样的,定义方法:listappear。实现获取关键词文本内容并显示。然后在前面添加信号:self.button_keylist.clicked.connect(self.listappear),进行信号和槽函数的关联。

7.编写完毕后,检查无问题,CMD窗口执行语句:Python openfile.py ,会自动调用Ui_openfile.py,这样一个小工具就初步告成了。

8.编译打包。有多个py文件时,主文件放在前面即可,打包命令:C:UsersadminAppDataLocalProgramsPythonPython37Scripts>pyinstaller -F openfile.py Ui_openfile.py
打包后生成exe文件,打开是闪退,提示错误: ImportError: unable to find Qt5Core.dll on PATH

经过查找,参考博客 https://blog.csdn.net/zwyact/article/details/99778898 ,添加一小段代码后解决。

使用PyQt5自制文件查找工具,并生成EXE文件

四.附录程序,注意缩进时,同一文本缩进方式要保持一致(TAB间缩进和四个空格缩进,只用一种)会省去编译报错的困扰:

报错信息:IndentationError: unexpected indent;IndentationError: expected an indented block

解决办法,可以用文本编辑器Notepad++把当前python脚本的所有空格或Tab字符都显示出来查看,视图 -> 显示符号 -> 显示空格与制表符,这样就能看到缩进方式了。

.主程序,很多异常都未写出来,后面逐步优化

import sys,os
if hasattr(sys, 'frozen'):
  os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH']
from PyQt5.QtWidgets import *
from Ui_openfile import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

file='//19.87.8.11/testtools/keywords.txt'
class MyMainWindow(QMainWindow,Ui_mainWindow):
  def __init__(self,parent=None):
    super(MyMainWindow,self).__init__(parent)
    self.setupUi(self)
  def loadtxt(self):                #打开文本选择路径框,获取目标文本
    filename,_=QFileDialog.getOpenFileName(self,'open file','.','txt(*.txt)')                         #QFileDialog是用于打开和保存文件的标准对话框
    def readtext(filename): #读取文本内容
      fullText = []
      textcon = open(filename, 'r', encoding='utf-8')                  #使用utf-8编码打开,非此编码的文本打开有问题,可以采用忽略错误的方式
      for i in textcon:
        lincone = i.strip()
        fullText.append(lincone)
        #print(fullText)
        return ' '.join(fullText)
      textcon.close()

    if filename:
      cur_path=QDir('.')
      relative_path = cur_path.relativeFilePath(filename)
      self.folderlist.setText(relative_path)                        #显示获取文本的路径
    self.goal=readtext(filename)

  def findtxt(self):
    j=0
    text_con=open(file, 'r', encoding='utf-8')                    #关键词所在的文本
    self.loadtxt()                                                             #调用获取目标文本内容函数
    goal_con=self.goal
    for i in text_con:
      line_cone = i.strip()
      #print(line_cone)
      j = j + 1
      if line_cone in goal_con:                                         #主程序中的关键程序,写了那么多,其他都是为了这个服务,南啊
        f=open('d:/list.txt','a',encoding='utf-8')
        f.write(str(j)+line_cone+' ')
    self.lineEdit.setText('结果已保存在D盘list.txt文件')             #结果提示

  def listappear(self):           #获取关键词文本内容,展示出来。
    fullText = ''         
    textcon = open(file, 'r', encoding='utf-8')
    for i in textcon:
      lincone = i.strip()
      fullText=fullText+lincone+','
    self.keylist.setText(fullText)     #设置的文本内容是个字符串,所以不能用前面的列表形式收集。
    textcon.close()

if __name__=="__main__":
  app=QApplication(sys.argv)  
  myWin=MyMainWindow()
  myWin.show()
  sys.exit(app.exec_())

2.ui文件

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'D:1.soft88.Python-Ericeric6worksecondwindow.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_mainWindow(object):
  def setupUi(self, mainWindow):
    mainWindow.setObjectName("mainWindow")
    mainWindow.resize(662, 430)
    self.centralwidget = QtWidgets.QWidget(mainWindow)
    self.centralwidget.setObjectName("centralwidget")
    self.button_keylist = QtWidgets.QPushButton(self.centralwidget)
    self.button_keylist.setGeometry(QtCore.QRect(80, 160, 121, 41))
    self.button_keylist.setObjectName("button_keylist")
    self.keylist = QtWidgets.QTextEdit(self.centralwidget)
    self.keylist.setGeometry(QtCore.QRect(230, 160, 251, 151))
    self.keylist.setObjectName("keylist")
    self.folderlist = QtWidgets.QLineEdit(self.centralwidget)
    self.folderlist.setGeometry(QtCore.QRect(230, 100, 401, 31))
    self.folderlist.setObjectName("folderlist")
    self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
    self.lineEdit.setGeometry(QtCore.QRect(230, 40, 241, 31))
    self.lineEdit.setObjectName("lineEdit")
    self.button_find = QtWidgets.QPushButton(self.centralwidget)
    self.button_find.setGeometry(QtCore.QRect(80, 40, 121, 31))
    self.button_find.setObjectName("button_find")
    self.button_openfile = QtWidgets.QPushButton(self.centralwidget)
    self.button_openfile.setGeometry(QtCore.QRect(80, 100, 121, 31))
    self.button_openfile.setObjectName("button_openfile")
    mainWindow.setCentralWidget(self.centralwidget)
    self.menubar = QtWidgets.QMenuBar(mainWindow)
    self.menubar.setGeometry(QtCore.QRect(0, 0, 662, 23))
    self.menubar.setObjectName("menubar")
    mainWindow.setMenuBar(self.menubar)
    self.statusbar = QtWidgets.QStatusBar(mainWindow)
    self.statusbar.setObjectName("statusbar")
    mainWindow.setStatusBar(self.statusbar)

    self.retranslateUi(mainWindow) 
    self.button_find.clicked.connect(self.findtxt)                   #信号signal
    self.button_keylist.clicked.connect(self.listappear)         #信号signal
    QtCore.QMetaObject.connectSlotsByName(mainWindow)

  def retranslateUi(self, mainWindow):
    _translate = QtCore.QCoreApplication.translate
    mainWindow.setWindowTitle(_translate("mainWindow", "关键字查询V1.0"))
    self.button_keylist.setText(_translate("mainWindow", "当前已有关键词"))
    self.lineEdit.setPlaceholderText(_translate("mainWindow", "结果保存在D盘list文本文件"))
    self.button_find.setText(_translate("mainWindow", "查找"))
    self.button_openfile.setText(_translate("mainWindow", "目标文件路径"))


if __name__ == "__main__":
  import sys
  app = QtWidgets.QApplication(sys.argv)
  mainWindow = QtWidgets.QMainWindow()
  ui = Ui_mainWindow()
  ui.setupUi(mainWindow)
  mainWindow.show()
  sys.exit(app.exec_())