川小胖学python

博客园 首页 新随笔 联系 订阅 管理

目录

一、背景介绍

二、代码及成果

三、代码分析

四、打包为exe

 

本实例主要使用了QTableWidget,openpyxl,利用openpyxl实现对excel文件的读取,QTableWidget实现对excel文件内容读取后,择需要信息在窗体上显示。之所以写该代码,是因为在同一项目的设计过程中(本人的工作是水工设计),常使用纬地软件设计多段道路,每段道路的数模都会生成土方计算表,软件的默认命名难以区分桩号,且挖填方量需要依次点开各个excel文件查看,不太方便。该段代码专门处理纬地软件生成的土方计算表,功能有

  • 自动获取桩号,并批量将文件以起止桩号重命名
  • 自动批量计算总挖填方,并将各段路的方量显示在QTableWidget中。

一、背景介绍

纬地软件生成的土方计算表通常会给定默认命名(如下图),我懒得一个个去改,但是仅根据默认据文件名难以确定是那段桩号的文件。如果改成以桩号来命名,方便最后统计工程量

纬地生成的土方计算表,同一个工作簿内通常有多个工作表,但最后一个是没有用的。需要从每个工作表的A列提取桩号,然后再倒数第二个工作表内提取累计的挖方量和填方量。

 

二、代码及成果

主要代码及操作界面如下

from PyQt5.QtWidgets import QWidget, QApplication, QFileDialog, QPushButton, QLineEdit, QHBoxLayout, \
    QVBoxLayout, QLabel, QTableWidget, QHeaderView, QTableWidgetItem
from PyQt5.QtGui import QIcon
import sys, os, openpyxl

path = os.path.dirname(os.path.dirname(__file__))


class MyWin(QWidget):

    def __init__(self):
        super(MyWin, self).__init__()
        self.initui()

    def initui(self):
        self.setWindowTitle('土方计算表计算')
        self.setWindowIcon(QIcon(r'%s\4.mypython\chuan.ico' % path))
        self.resize(600, 500)

        btn_open = QPushButton('打开文件')
        btn_rename = QPushButton('重命名')
        lbl_excavation = QLabel('总挖方量', self)
        lineedit_excavation = QLineEdit()
        lbl_fill = QLabel('总填方量', self)
        lineedit_fill = QLineEdit()
        tableWidget = QTableWidget()

        # =======布局======
        hbx1 = QHBoxLayout()
        hbx1.addWidget(lbl_excavation)
        hbx1.addWidget(lineedit_excavation)
        hbx1.addWidget(lbl_fill)
        hbx1.addWidget(lineedit_fill)
        hbx1.addWidget(btn_open)
        hbx1.addWidget(btn_rename)

        vbx = QVBoxLayout()
        vbx.addWidget(tableWidget)
        vbx.addLayout(hbx1)
        self.setLayout(vbx)

        btn_rename.clicked.connect(self.rename_files)
        btn_open.clicked.connect(lambda: self.open_files(lineedit_excavation, lineedit_fill, tableWidget))  # 调用函数
        # btn_open.clicked.connect(lambda: self.table_init(tableWidget))

    def rename_files(self):
        f_names, _ = QFileDialog.getOpenFileNames(self, '打开文件', 'D:\\', 'XLSX Files(*.xlsx)')
        if f_names:  # f_names返回值为列表,元素为文件地址
            for f_name in f_names:
                wb = openpyxl.load_workbook(f_name)  # 打开工作簿
                stake_numbers = []
                for sheetname in wb.sheetnames[:-1]:  # 依次获取工作表,提取起止桩号。最后一个工作表无内容,因此舍去
                    ws = wb[sheetname]
                    stake_numbers += [i.value for i in ws['A'] if i.value != None][4:-2]  # 获取桩号列表
                start_station, end_station = stake_numbers[0], stake_numbers[-1]  # 赋值起点桩号和终点桩号
                os.rename(f_name.split('/')[-1], '%s~%s.xlsx' % (start_station, end_station))  # os.rename(旧名字,新名字)

    def open_files(self, lineedit_excavation, lineedit_fill, table):
        f_names, _ = QFileDialog.getOpenFileNames(self, '打开文件', 'D:\\', 'XLSX Files(*.xlsx)')
        if f_names:
            total_excavation, total_fill = 0, 0
            self.quantity_all = []  # 起止桩号和挖填方
            for f_name in f_names:
                wb = openpyxl.load_workbook(f_name, data_only=True)  # 只返回数值,不返回公式
                # cell_range = ws['A1':'C2'] #通过切片访问多个单元格
                ws = wb[wb.sheetnames[-2]]
                quantity_fill, quantity_excavation = ws['R37'].value, ws['E37'].value
                total_excavation += quantity_excavation
                total_fill += quantity_fill

                stake_numbers = []
                for sheetname in wb.sheetnames[:-1]:  # 依次获取工作表,提取起止桩号。最后一个工作表无内容,因此舍去
                    ws = wb[sheetname]
                    stake_numbers += [i.value for i in ws['A'] if i.value != None][4:-2]  # 获取桩号列表
                start_station, end_station = stake_numbers[0], stake_numbers[-1]  # 赋值起点桩号和终点桩号

                self.quantity_all.append(
                    [start_station, end_station, round(quantity_excavation, 2), round(quantity_fill, 2)])
            lineedit_excavation.setText(str(round(total_excavation, 2)))  # 必须转换为字符串才能赋值
            lineedit_fill.setText(str(round(total_fill, 2)))  # 必须转换为字符串才能赋值
            self.table_init(table)

    def table_init(self, table):
        table.setColumnCount(4)
        table.setRowCount(len(self.quantity_all))
        table.setHorizontalHeaderLabels(['起点桩号', '终点桩号', '挖方量', '填方量'])
        table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # print(self.quantity_all)
        for i in range(len(self.quantity_all)):
            for j in range(4):
                newitem = QTableWidgetItem(str(self.quantity_all[i][j]))  # 必须转成字符串,否则不报错,也不显示
                table.setItem(i, j, newitem)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWin()
    win.show()
    sys.exit(app.exec_())
批量处理土方计算表

处理后的文件:

三、代码分析

f_names, _ = QFileDialog.getOpenFileNames(self, '打开文件', 'D:\\', 'XLSX Files(*.xlsx)')

  这里_为占位符,f_names范围的是元组,元素为各个文件的绝对路径。如果使用getOpenFileName就只能打开单个文件,getOpenFileNames可以打开多个文件,实现批量处理。

stake_numbers += [i.value for i in ws['A'] if i.value != None][4:-2]

  这里使用了列表生成器,if i.value != None可以将空白单元格排除掉

wb = openpyxl.load_workbook(f_name, data_only=True)

  这里必须加data_only=True,因为excel里有些单元格是有公式的,不加这个返回的就是单元格的公式而不是单元格的值。

table.setRowCount(len(self.quantity_all)) #行数随文件自动变化
table.setHorizontalHeaderLabels(['起点桩号', '终点桩号', '挖方量', '填方量'])
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) #列宽自动拉伸

 

四、打包为exe

可以使用pyinstaller将代码打包为exe。windows平台打包后,想要运行时不弹出cmd窗口,步骤如下,

1.将文件名改为pyw后缀,例如“表格.py”改为“表格.pyw”

2.启动cmd,切换到py文件所在目录

3. 输入pyinstaller -F 表格.pyw --noconsole 这里的“表格.pyw”是要打包的py文件名,“--noconsole”必须要加上,这样程序运行时不会弹出cmd窗口

 

posted on 2020-11-14 00:07  川小胖学Python  阅读(1085)  评论(0编辑  收藏  举报