基于pyqt5的csv文件处理程序

  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

      下面附上一些还不错的相关链接:

       python Numpy库简单教程

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()

      下面附上一些还不错的相关链接:

      PyQt5学习随笔

      使用PyQt来编写第一个Python GUI程序

      PyQt5使用Designer设计UI的两种实现方式

      PyQt简单例子: 包括ui文件生成, 代码, 打包exe

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的连接:

      关于QT的系统总结

      tkinter book

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等),之前在网上搜索过,相关链接没有记录下来。我自己使用时,发现程序文件在不同的文件

查看方式(超大图标,大图标,中等图标,小图标,详细信息等),需要以不同的分辨率的图标显示。

     为了解决应用程序图标问题,我们可以通过网络下载图标文件,自己制作图标文件。附上几个有用链接。

    pyinstaller 使用的文档说明

    CSDN网友的blog “使用pyinstaller打包Python3.5+PyQt5.6项目生成exe文件”

    进行图标转换的网站convert icon   (可进行转换的文件格式有jpeg, png等)

    进行图标转换和图标下载的网站easy icon   

2.5 其他信息

    其他待补充的信息,暂时未想到。

    项目代码部分,可移步github查看,链接:https://github.com/python-leo/python-csv-handler-pyqt5

   

可以通过Python自带的csv模块csv文件,然后使用PyQt5的QTableView控件来显示csv文件中的数据。以下是一个csv文件并将其显示在QTableView中的示例代码: ```python import csv from PyQt5.QtWidgets import QApplication, QTableView from PyQt5.QtCore import Qt, QAbstractTableModel class CsvModel(QAbstractTableModel): def __init__(self, data): QAbstractTableModel.__init__(self) self._data = data def rowCount(self, parent=None): return len(self._data) def columnCount(self, parent=None): if len(self._data) > 0: return len(self._data[0]) return 0 def data(self, index, role): if not index.isValid(): return None if role == Qt.DisplayRole: return self._data[index.row()][index.column()] def headerData(self, section, orientation, role): if role != Qt.DisplayRole: return None if orientation == Qt.Horizontal: return "Column %d" % section else: return "Row %d" % section class CsvViewer(QTableView): def __init__(self, data): QTableView.__init__(self) self.model = CsvModel(data) self.setModel(self.model) if __name__ == '__main__': with open('data.csv', 'r') as file: reader = csv.reader(file) data = list(reader) app = QApplication([]) view = CsvViewer(data) view.show() app.exec_() ``` 在上面的代码中,我们首先通过Python自带的csv模块csv文件,然后将其转化为一个二维列表。接着,我们定义了一个CsvModel类,该类继承自QAbstractTableModel,用于将取的csv数据转化为一个可以在QTableView中显示的模型。最后,我们定义了一个CsvViewer类,该类继承自QTableView,用于显示CsvModel中的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值