1. 程序的简要介绍
这个工具软件,是通过python实现,用来读取,解析特定内容格式的csv文件。将读取的行,列
写入csv文件。程序逻辑很简单,使用python提供的csv reader逐行读取csv文件。当然,使用pandas库来处理
表格数据,应该也是挺有效的。使用pyqt5实现GUI部分。需要注意的是,如果没有qt基础,使用pyqt5时很容易
遇到问题。例如:在显示弹出窗口的时候,会使用object.show()(或者 object.exec())。而这个object类型,
需要注意,可以是QDialog,也可以是QMainWindow。在没有弄清楚 正确的使用方法前,很多人跟我之前一样,
盲目,错误地参考了网上的示例代码,使用了self.show()。
工具主界面(添加文件,点击按钮开始处理csv文件)如下:
正确处理数据的对话框如下所示:
选择的文件不正确时,错误提示框如下:
下面将从4个方面对程序中需要注意的点进行介绍。
csv file reading and parsing
process data GUI
result dialog GUI
将python程序打包成exe
2. 代码解读和部分要点说明
2.1 csv file reading and parsing
python csv reader在读取csv文件时,读取的每一行都是一个List。而这个List中的每一个元素都被
视作string。 我们不能通过读取文本文件的行结束符"\r\n"(Windows系统)或者"\n"(Linux系统)
来确定一行读取完毕。 但我们可以通过len(ListA)确定一行读取的列数。
下面简要列举一下代码中要注意的点:
(1)如果使用到全局的string list,记得在填充元素之前,进行清空操作。
result_str = []
def clear_csv_data_buf(self):
self.result_str.clear()
(2)可以根据文件里面的特定信息(如第一行内容)判断文件内容格式是否正常。 在使用特定的行,列
内容进行判断的时候,需要确保该行,列是存在的,因为读入 的文件,也可能是错误的。记得添加错误处理
(error handling)。示例如下:
if (row_sel == 0):
if (len(row) >= 3 and row[2].rfind("Colorcheck") != -1) or (
len(row) >= 4 and row[3].rfind("Colorcheck") != -1):
pass
else:
return -(i + 1)
(3)其他错误处理(error handling)。这些都不困难,都是一些用户逻辑处理。下面举例说明:
当添加文件后,点击“处理csv数据”按钮时,如果文件不存在(如路径被修改,文件被删除)怎么办?
写入文件的时候,如果文件正被打开,该怎么办? 使用with ... open,只能确保文件被关闭,并不能正确的
处理上述异常。
try:
with open(file_path, mode='w', newline='') as fd_write_result_csv:
writer = csv.writer(fd_write_result_csv)
writer.writerow(file_path_title)
writer.writerow([]) # add blank line to sep different content
# writer.writerows(self.result_str)
for i in self.result_str:
writer.writerow(i)
except IOError:
print("Result file is opened, please close it before writing contents")
return -10
选择的文件不是.csv文件怎么办?
if os.path.splitext(shading_file_list[0])[1] != '.csv':
return -10
用户什么文件都不添加,直接点击“处理csv数据”按钮怎么办?
if color_file_count == 0 and shading_file_count == 0 and step_file_count == 0: # file_save_path is None:
print(" No file is selected to process, do nothing")
error_str = "错误:没有添加任何文件"
self.result_dialog.setup_ui_notify_error(self.test_result_dlg, error_str)
self.test_result_dlg.show()
return
下面附上一些还不错的相关链接:
2.2 process data GUI
使用pyqt5实现GUI。在GUI绘制和逻辑控制方面,还是有些小坑值得说明的。
(1)网上很多人说使用qtdesigner进行可视化图形界面设计及UI代码自动生成。真的太坑了,因为实际上
QT Designer对应的程序是designer.exe,不是qt designer。害我安装了两三次pyqt5。
(2)在你所安装的版本的python路径下搜索pyuic,将designer自动生成的ui文件,转换为python文件。
示例如下:pyuic5.exe -o ui_Login.py Login.ui
(3)在main函数中创建qt Application,Main window,并在Main Window上绘制GUI组件。如下:
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main_window = QtWidgets.QMainWindow()
main_ui = your_ui_class()
main_ui.setupUi(main_window)
main_window.show()
sys.exit(app.exec_())
需要说明的是,setupUI里面完成创建GUI组件等事情。该函数可以放到类的初始化方法中。当对象创建时,
__init__方法被调用。注意__init__的编写方法,特别是父类的初始化方式。
示例1 (父类为QMainWindow):
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
示例2 (父类为QDialog):
class Login(QDialog):
"""登录窗口"""
def __init__(self, *args):
super(Login, self).__init__(*args)
loadUi('Login.ui', self) #看到没,瞪大眼睛看
self.labelTips.hide()
self.pushButtonOK.clicked.connect(self.slotLogin)
self.pushButtonCancle.clicked.connect(self.slotCancle)
示例3(父类为QDialog):
class my_result_dialog(QDialog):
def __init__(self):
super(QDialog, self).__init__()
self.result_window = QtWidgets.QMainWindow()
pass
示例4(父类为QWidget)
class BaiduDiskToolWidget(QWidget):
def __init__(self):
super(BaiduDiskToolWidget, self).__init__()
self.mywidgetui = baidudisktool_ui.Ui_Form()
self.mywidgetui.setupUi(self)
self.mywidgetui.pushButtonBaiduOpen.clicked.connect(self.__slotOpenUrl) # 信号与槽连接
self.mywidgetui.pushButtonBaiduCopy.clicked.connect(self.__slotCopyUrl) # 信号与槽连接
self.board = QGuiApplication.clipboard()
下面附上一些还不错的相关链接:
2.3 result dialog GUI
(1)关于设置文本的字体大小,颜色,可以直接使用对应的方法,不一定需要paletee。如下:
self.textEdit_2_color_test_result = QtWidgets.QTextEdit(Dialog_CSV_Data_Result)
self.textEdit_2_color_test_result.setGeometry(QtCore.QRect(60, 210, 341, 61))
self.textEdit_2_color_test_result.setObjectName("textEdit_2_color_test_result")
self.textEdit_2_color_test_result.setTextColor(QtGui.QColor(200, 0, 0))
self.textEdit_2_color_test_result.setTextColor(QtGui.QColor(0, 200, 0))
# self.textEdit_2_color_test_result.setFont(QFont("Times", 12, QFont.Normal))
self.textEdit_2_color_test_result.setFontPointSize(16)
text_str = "总共:添加%d个色彩测试文件" % abs(self.color_test_file_count)
self.textEdit_2_color_test_result.setText(_translate("Dialog_CSV_Data_Result", text_str))
(2)python编译,运行经常会遇到奇怪的错误,如:程序按照非预期的方式结束运行。UI组件或者
窗口并没有按照预期显示出来。 出现错误时,PyCharm并不会给出具体的错误说明,对于新手,
可能不得不添加较多的log,来确定问题出现在哪行。
(3)因为代码遗漏,导致对话框没有成功显示。如下:
self.textEdit_2_color_test_result.setTextColor(QtGui.QColor(200, 0, 0))
self.textEdit_2_color_test_result.setTextColor(QtGui.QColor(0, 200, 0))
# self.textEdit_2_color_test_result.setFont(QFont("Times", 12, QFont.Normal))
self.textEdit_2.setFontPointSize(16)
text_str = "总共:添加%d个色彩测试文件" % abs(self.color_test_file_count)
self.textEdit_2_color_test_result.setText(_translate("Dialog_CSV_Data_Result", text_str))
原本以为:setFont或者setFontPointSize这种方法,即便没有调用,都不会影响对话框是否显示。
那么,上面虽然因为编写错误,使用了错误的类成员textEdit_2而不是textEdit_2_color_test_result,
那也不应该会影响显示,毕竟这个新的textEdit_2并没有创建。
结果是:对话框因为该语句的错误而无法成功显示。个人猜测原因可能是因为这个textEdit_2没有创建,
所以不能调用类方法。
(4)关于在当前窗口弹出另外的窗口(或者对话框)的实现方式,不要简单的套用网上的示例代码, 如
Class test_a:
def button_clicked(self):
result_dlg = my_result_ui(self)
self.show()
上面的代码,错误至少有2处:(I)定义的局部变量result_dlg生命周期段,函数执行结束后,局部变量生命周期
结束,变量被释放。我们会看到对话框显示后闪退。(II)传入my_result_ui的self,作用是什么?后续对话框的显示
需要依赖它吗?
显示的新对话框,可以放到QDialog对象上,也可以放到另外的一个QMainWindow对象上。
(4-1)新对话框 基于 QDialog, 需要创建QDialog对象。示例代码如下:
class Ui_Dialog_Camera_CSV_Proc(QDialog):
test_result_dlg = None
def process_csv_data(self):
self.result_dialog = Ui_Dialog_CSV_Data_Result()
self.test_result_dlg = QDialog()
self.result_dialog.setup_ui_notify_error(self.test_result_dlg)
self.test_result_dlg.exec()
class Ui_Dialog_CSV_Data_Result(QDialog):
def setup_ui_notify_error(self, Dialog_CSV_Data_Result):
Dialog_CSV_Data_Result.setObjectName("Dialog_CSV_Data_Result")
Dialog_CSV_Data_Result.resize(470, 557)
(4-2)新对话框 基于 QMainWindow, 需要创建QMainWindow对象。示例代码如下:
class Ui_Dialog_Camera_CSV_Proc(QDialog):
test_result_dlg = None
def process_csv_data(self):
self.result_dialog = Ui_Dialog_CSV_Data_Result()
self.test_result_dlg = QDialog()
self.result_dialog.setup_ui_notify_error(self.result_dialog.result_window)
self.result_dialog.result_window.exec()
class Ui_Dialog_CSV_Data_Result(QDialog):
result_window = None
def __init__(self):
super(QDialog, self).__init__()
self.result_window = QtWidgets.QMainWindow()
pass
def setup_ui_notify_error(self, Dialog_CSV_Data_Result):
Dialog_CSV_Data_Result.setObjectName("Dialog_CSV_Data_Result")
Dialog_CSV_Data_Result.resize(470, 557)
由于之前也试着使用tkinter完成了简单的GUI,所以,在这里也附带一个不错的tkinter的连接:
2.4 将python程序打包成exe
Java程序可以打包成可执行程序(.exe文件),python程序也可以。可以使用p2exe或者pyinstaller来完成打包。关于
py2exe,有兴趣的同学可以网上搜索一下。我能搜到的资料是:该库比较陈旧,可以支持的python版本不够新。官方
网站上看到的最新支持版本还是python 2.x。进一步搜索后,找到了某个 个人开发者自己实现的py2exe,可以支持
python 3.4版本,好像没有支持更新的版本。一番考量后,还是使用了当下被使用较多的pyinstaller来打包。
使用方法如下:
pyinstaller [options] script [script …] | specfile
-c, --console, --nowindowed
Open a console window for standard i/o (default)
-w, --windowed, --noconsole
Windows and Mac OS X: do not provide a console window for standard i/o. On Mac OS X this also triggers
building an OS X .app bundle. This option is ignored in *NIX systems.
-i <FILE.ico or FILE.exe,ID or FILE.icns>, --icon <FILE.ico or FILE.exe,ID or FILE.icns>
FILE.ico: apply that icon to a Windows executable. FILE.exe,ID, extract the icon with ID from an exe.
FILE.icns: apply the icon to the .app bundle on Mac OS X
-D, --onedir Create a one-folder bundle containing an executable (default)
-F, --onefile Create a one-file bundled executable.
示例如下:
pyinstaller -i test01.ico -w -F data_proc.py
我们常常习惯于直接点击exe运行程序,所以我建议个人开发者使用-F,-w选项。使用-i选项指定程序图标。需要说明的是,
“.ico”文件里面实际上包含了多个不同分辨率的图标文件,至于windows下需要哪些分辨率(如64 x 64, 48 x 48,
32 x 32, 16 x 16等),之前在网上搜索过,相关链接没有记录下来。我自己使用时,发现程序文件在不同的文件
查看方式(超大图标,大图标,中等图标,小图标,详细信息等),需要以不同的分辨率的图标显示。
为了解决应用程序图标问题,我们可以通过网络下载图标文件,自己制作图标文件。附上几个有用链接。
CSDN网友的blog “使用pyinstaller打包Python3.5+PyQt5.6项目生成exe文件”
进行图标转换的网站convert icon (可进行转换的文件格式有jpeg, png等)
2.5 其他信息
其他待补充的信息,暂时未想到。
项目代码部分,可移步github查看,链接:https://github.com/python-leo/python-csv-handler-pyqt5