闲来无事,写个给表格分组或合并的小工具
玩python 时间也不长,有时办公要用到EXCEL里不断重复的分组,合并数据,ctrl+v,ctrl+c ,搞的手指发麻,于是就抽空搞了这么个小工具,用的是pandas,网上,同时也借用了一些大佬的作品,揉合而成。放在这与大家共勉,一起学习,bug不断,欢迎留下脚印。from PyQt5.QtNetwork import QLocalSocket, QLocalServer# 实例化程式,只许一个运行
from PyQt5 import QtCore
from PyQt5.QtGui import QTextCursor, QColor
from PyQt5.QtWidgets import *
#from PyQt5.QtWidgets import QApplication, QFileDialog
import sys,os
import pandas as pd
from PyQt5.QtWidgets import QApplication, QComboBox, QDialog, QVBoxLayout, QLabel, QPushButton,QFileDialog
from win32com.client import Dispatch
import openpyxl
class ComboCheckBox(QComboBox):
def __init__(self, items: list):
"""
initial function
:param items: the items of the list
"""
super(ComboCheckBox, self).__init__()
self.items = ["全选"] + items# items list
self.box_list = []# selected items
self.text = QLineEdit()# use to selected items
self.state = 0# use to record state
q = QListWidget()
for i in range(len(self.items)):
self.box_list.append(QCheckBox())
self.box_list.setText(self.items)
item = QListWidgetItem(q)
q.setItemWidget(item, self.box_list)
if i == 0:
self.box_list.stateChanged.connect(self.all_selected)
else:
self.box_list.stateChanged.connect(self.show_selected)
q.setStyleSheet("font-size: 30px; font-weight: bold; height: 50px; margin-left: 15px")
#self.setStyleSheet("width: 300px; height: 50px; font-size: 21px; font-weight: bold")
self.text.setReadOnly(True)
self.setLineEdit(self.text)
self.setModel(q.model())
self.setView(q)
def all_selected(self):
"""
decide whether to check all
:return:
"""
# change state
if self.state == 0:
self.state = 1
for i in range(1, len(self.items)):
self.box_list.setChecked(True)
else:
self.state = 0
for i in range(1, len(self.items)):
self.box_list.setChecked(False)
self.show_selected()
def get_selected(self) -> list:
"""
get selected items
:return:
"""
ret = []
for i in range(1, len(self.items)):
if self.box_list.isChecked():
ret.append(self.box_list.text())
return ret
def show_selected(self):
"""
show selected items
:return:
"""
self.text.clear()
ret = '; '.join(self.get_selected())
self.text.setText(ret)
class MyDialog(QDialog):
def __init__(self):
#定义列名列表大A-Z
col_list = list(map(chr, range(65, 91)))
self.file_name = ''
self.output = 'output.xlsx'# 输出OUT表
#self.win__dir = os.environ['HOMEPATH'] + '//' + 'Desktop'# 打开文件默认活动桌面
# RC = read.read_config(self=read)# 传总参,导入配置文件,为后面的参数做基础
# 传参,导入压缩图片类和其参数(参数读取自配置文件)
# self.Result = result.Compress_img(RC.get('api', 'rate'), RC.get('api', 'quality'), RC.get('api', 'way'))
# self.url = RC.get('api', 'url')#从配置文件提参数get示例
####sytext水印文字
# sytext = RC.get('sylogo','sytime')+'\n'+RC.get('sylogo', 'syadd')+'\n'+RC.get('sylogo', 'syen')
super().__init__()
"""控件的创建和布局"""
########1。先创建按键筐
#self.lineEdit = QLineEdit("")# 路经显示
self.textEdit = QTextEdit()# 富文本显示
###################################
self.pushExcel = QLabel("Excel表:")
#self.pushExcel.setMinimumWidth(100)
self.lineExcel = QLineEdit("")# 路经显示
#self.lineExcel.setMinimumWidth(100)
self.selExcel = QPushButton("请选择")
#self.selExcel.setMinimumWidth(100)
################################
self.pushGroup = QLabel("分组列: ")
#self.pushGroup.setMinimumWidth(50)
#self.listGroup = QLineEdit("")# 路经显示
self.listGroup = ComboCheckBox(col_list)
# self.listGroup.setMinimumWidth(300)
########################
self.pushMerge = QLabel("合并列: ")
#self.pushMerge.setMinimumWidth(50)
#self.listMerge = QLineEdit("")# 路经显示
self.listMerge = ComboCheckBox(col_list)
#self.listMerge.setMinimumWidth(50)
#########################
self.pushGO = QPushButton("开始处理")
#self.pushGO.setMinimumWidth(50)
self.pushSee = QPushButton("结果查询")
#self.pushSee.setMinimumWidth(50)
######################2.创建第一排水平表单布局
self.hflo0 = QFormLayout()# 创建水平表单布局
self.hflo1 = QFormLayout()# 创建水平表单布局
self.hflo2 = QFormLayout()# 创建水平表单布局
######################2.1创建第二排水平表单布局
self.hflo11 = QFormLayout()# 创建水平表单布局
self.hflo12 = QFormLayout()# 创建水平表单布局
######################2.1创建第三排水平表单布局
self.hflo21 = QFormLayout()# 创建水平表单布局
self.hflo22 = QFormLayout()# 创建水平表单布局
######################2.1创建第四排水平表单布局
self.hflo31 = QFormLayout()# 创建水平表单布局
self.hflo32 = QFormLayout()# 创建水平表单布局
###############3.将第一排水平表单和按键结合
self.hflo0.addRow(self.pushExcel)
self.hflo1.addRow(self.lineExcel)
self.hflo2.addRow(self.selExcel)
###############3.1将第二排水平表单和按键结合
self.hflo11.addRow(self.pushGroup)
self.hflo12.addRow(self.listGroup)
###############3.1将第三排水平表单和按键结合
self.hflo21.addRow(self.pushMerge)
self.hflo22.addRow(self.listMerge)
###############3.1将第4排水平表单和按键结合
self.hflo31.addRow(self.pushGO)
self.hflo32.addRow(self.pushSee)
################4.创建垂直表单布局 路经显示和富文本
self.vflo = QFormLayout()# 创建垂直表单布局 路经显示和富文本
#self.vflo.addRow(self.lineEdit)
self.vflo.addRow(self.textEdit)
################5. 添加水平布局第一排(也可以再加一排)
self.hbox = QHBoxLayout()
self.hbox.addLayout(self.hflo0)
self.hbox.addLayout(self.hflo1)
self.hbox.addLayout(self.hflo2)
self.hbox.setSpacing(0)
################5.1 添加水平布局第二排(也可以再加一排)
self.hbox2 = QHBoxLayout()
self.hbox2.addLayout(self.hflo11)
self.hbox2.addLayout(self.hflo12)
self.hbox2.setSpacing(0)
################5.1 添加水平布局第三排(也可以再加一排)
self.hbox3 = QHBoxLayout()
self.hbox3.addLayout(self.hflo21)
self.hbox3.addLayout(self.hflo22)
self.hbox3.setSpacing(0)
################5.1 添加水平布局第4排(也可以再加一排)
self.hbox4 = QHBoxLayout()
self.hbox4.addLayout(self.hflo31)
self.hbox4.addLayout(self.hflo32)
self.hbox4.setSpacing(0)
###############6. 添加垂直布局
self.vbox = QVBoxLayout()
self.vbox.addLayout(self.vflo)
# self.vbox.addLayout( self.vfl1 )
###################### 添加布局
vlayout = QVBoxLayout()# 整个程序的灵魂,将QVBoxLayout改成QHBoxLayout可以改变hbox和vbox的布局从垂直布局到水平布局
vlayout.addLayout(self.hbox)# 组合第一排
vlayout.addLayout(self.hbox2)# 组合第二排
vlayout.addLayout(self.hbox3)# 组合第二排
vlayout.addLayout(self.hbox4)# 组合第二排
vlayout.addLayout(self.vbox)# 组合第三列
self.setLayout(vlayout)
self.textEdit.setFontPointSize(15)# 设置富文本的字体大小
self.textEdit.setReadOnly(False)# 设置为只读、可写
self.textEdit.setTextBackgroundColor(QColor(80, 80, 80))# 设置文字背景色
self.textEdit.setTextColor(QColor(200, 220, 180))# 设置文字颜色
################################################
"""信号绑定"""###信号绑定必须也函数一一对应,否则不显示窗口
self.selExcel.clicked.connect(self.choose_file)# 选择文件
self.pushGO.clicked.connect(self.load_file)#执行文件
self.pushSee.clicked.connect(self.load_See)#查绚结果
# # self.jsGO.clicked.connect(self.__onClickejyGO) #极速录单
# self.chromedebug.clicked.connect(self.__chromedebug)# 谷歌浏览器
# self.pushIMGSY.clicked.connect(self.__pushIMGSY)# 图片压缩
# #self.lineEdit.clicked.connect(self.__lineEdit)# 图片压缩
# self.lineEdit.returnPressed.connect(self.__lineEdit)#路经显示回车激活函数
#####################################################################
def choose_file(self):
try:
'''选择EXCEL文件'''
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
file_name, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel files (*.xlsx)", options=options)
if file_name:
# print(file_name)
self.lineExcel.setText(file_name)
self.file_name = file_name
df = pd.read_excel(self.file_name)
# 读取原表的列名并生成列表
list_df = list(df)
# 以原列列表为基础,生成大写字母的同量列表
list_dfmap = list(map(chr, range(65, 65 + len(list_df))))
# 交两个列表合并生成新的对应字典,方便后面以大写字母调用列名
Clist = dict(zip(list_dfmap, list_df))
print(Clist)
self.textEdit.setText('提示:从下面的对应关系上选择分组与合并列\n'+ str(Clist))
except:
print('文件选择出错')
def load_file(self):
try:
self.close_excel_file(self.output)
'''加载EXCEL文件,写入列表名'''
print('开始载入列名')
# 读取Excel文件
if len(self.file_name) <=0:
print('请选择需要处理的表格文件')
QMessageBox.information(self, '提示', "请选择需要处理的表格文件")
else:
print(self.file_name)
#读取表格内容,并将Dataframe利用applymap(str)函数全部转为字符串格式,以防报错
df = pd.read_excel(self.file_name).applymap(str)
# 读取原表的列名并生成列表
list_df = list(df)
# 以原列列表为基础,生成大写字母的同量列表
list_dfmap = list(map(chr, range(65, 65 + len(list_df))))
# 交两个列表合并生成新的对应字典,方便后面以大写字母调用列名
Clist = dict(zip(list_dfmap, list_df))
print(Clist)
#读取分组的列名大写字母
see_Group = self.listGroup.get_selected()
# 读取合并的列名大写字母
see_Merge = self.listMerge.get_selected()
# 跟据用户选择的分组,合并列的大写字木,在字母列名的字典里读取出来,生成各自列表
hb_name = list(Clist.get(i) for i in see_Group)
hb_value = list(Clist.get(i) for i in see_Merge)
print(hb_name)
print(hb_value)
#检查分组和合并两个列表是否有交集,并返回交集
list_c = list(set(see_Group) & set(see_Merge))
print(list_c)
# 通过交集列表长度判断,如果有交集则返回提示信息,否则执行后面操作
if len(list_c) >= 1:
QMessageBox.information(self, '提示', "分组与合并列不能有重合{}".format(list_c))
else:
print('开始进行分组合并操作')
if len(see_Group) >=1:
print('分组列非空,执行下面代码')
if len(see_Merge) >=1:
print('合并列非空,执行分组合并任务')
# 生成合并字典式,value_y为合并里面的代码,只能用字典
value_y = {'one': lambda x: '、'.join(set(x))}
# print(value_y)
print(value_y)
# 通常用来初始化字典, 设置value的默认值,
value = dict.fromkeys(hb_value, value_y.get('one'))
# 按照hb_name列进行分组,并将hb_value里的所有列分别合并为一个逗号分隔的字符串,同时去重,转换为DataFrame
# result = df.groupby(hb_name).agg(value)
result = df.groupby(hb_name).agg(value)
# 将原数据按名子分组
df1 = df.drop_duplicates(subset=hb_name)
# 将result与原始数据按照name列进行合并,保留其他列的内容
result = pd.merge(df1.drop(columns=hb_value).drop_duplicates(), result, on=hb_name)
# 按最原表的列顺序展示新表,list_df为原表的列表
result = result
print(result)
result.to_excel(self.output, index=False)
QMessageBox.information(self, '提示', "以{}分组,以{}合并完成".format(hb_name,hb_value))
else:
print('合并列为空,单执行分组任务')
# 将原数据按名子分组
hb_Group = df.drop_duplicates(subset=hb_name)
print(hb_Group)
hb_Group.to_excel(self.output, index=False)
QMessageBox.information(self, '提示', "以{}分组完成".format(hb_name))
else:
print('分组列为空,请选择')
QMessageBox.information(self, '提示', "分组列为空,请选择")
except:
print('执行分组合并出错')
def load_See(self):
try:
#查询结果
print("查询结果开始")
# 打开查询到的数据表格
print(self.output)
os.startfile(self.output)
#self.close_excel_file(self.output)# 关掉OUT表
except:
print('查询结果出错')
def close_excel_file(self,closeexcel):
#关掉指定的表格文件
xlApp = Dispatch('Excel.Application')
xlApp.DisplayAlerts = False# 设置不显示警告和消息框
# xlBook = xlApp.Workbooks.Open(file)
workbooks_n = xlApp.Workbooks.Count
print(f'已打开工作簿的数量为:{workbooks_n}个')
if workbooks_n < 0: return
for i in range(1, workbooks_n + 1):# 工作簿索引从1开始
path_ = xlApp.Workbooks(i).Path
name_ = xlApp.Workbooks(i).Name
path = path_ + "\\backup_" + name_
# print(f'第{i}个excel的文件路径为:{path}')
if (closeexcel in path):
xlApp.Workbooks(i).Close() #关闭当前打开的文件,不保存文件
# xlApp.Workbooks(i).Activate()
#xlApp.Workbooks(i).SaveAs(path)
#xlApp.Workbooks(path).Close()
# xlApp.Quit()#关闭所有打开的excel文件
del xlApp
if __name__ == "__main__":
try:
app = QApplication(sys.argv)
serverName = 'testEvaluatinoServer601'
socket = QLocalSocket()
socket.connectToServer(serverName)
# 如果连接成功,表明server已经存在,当前已有实例在运行
if socket.waitForConnected(601):
app.quit()
else:
localServer = QLocalServer()# 没有实例运行,创建服务器
localServer.listen(serverName)
dialog = MyDialog()
dialog.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)# 窗口置顶
dialog.show()
dialog.setWindowTitle('Excel分组合并 by.182294401')
# dialog.move( int( rc.read_config() ), int( rc.read_config() ) )# 窗口靠右
#dialog.resize(600, 500)# 显示框大小
sys.exit(app.exec_())
pass
except:
pass
有没有一个浅显的功能说明? 这个是怎么使用,来个功能简介 来个成品 感谢 感谢分享{:1_921:} 咳,拿来主义了解下PyQt keithu 发表于 2023-5-17 23:16
有没有一个浅显的功能说明?
首先选择需要操作的表格,1.按列名分组,可以一列也可以多列,2.在分组的基础上,合并需要的列的数据,并以顿号分开,同时去掉重复数据。 分享成品下截地址:https://share.weiyun.com/XilMJc4u
收藏一下,后续使用
页:
[1]