当前位置:网站首页>Merge two excel spreadsheet tools
Merge two excel spreadsheet tools
2022-08-03 01:32:00 【Andy Dennis】
前言
We sometimes need to merge two related tables.例如表格1有“考生号, 姓名, 语文成绩”字段,表格2有“考生号, 姓名, 数学成绩”,So now you need to merge two form as “考生号, 姓名, 语文成绩, 数学成绩”.

示例
原来a, b表格


导出后:
代码
main.py
""" Author: Andy Dennis Date: 2022.7.29 Details: 其中ComBoPicker代码来自https://blog.csdn.net/weixin_45774074/article/details/123293411 """
from tkinter import *
import tkinter as tk
from ComBoPicker import Combopicker# Import custom drop-down boxes,
import tkinter.font as tf
from tkinter import filedialog, messagebox
import traceback
import pandas as pd
main_xlsx = ''
aux_xlsx = ''
join_df = None
# Select the main table
def select_main_xlsx():
global main_xlsx
global join_df
fp = filedialog.askopenfilename(title=u'Please select the main table')
print(fp)
try:
if fp is not None and len(fp) > 0:
if fp.split('.')[-1] not in ['xls', 'xlsx']:
tk.messagebox.showerror('error', '请选择xls/xlsx的文件')
return
main_xlsx = fp
lb1['text'] = fp
join_df = None
print('main_xlsx: ', main_xlsx)
lb5['text'] = 'No hint'
# tk.messagebox.showinfo('success', '选择原始目录成功')
else:
tk.messagebox.showerror('error', 'Please select the main failure')
except:
tk.messagebox.showerror('error', 'Please select the main failure')
print(traceback.format_exc())
# Select the side tables
def select_aux_xlsx():
global aux_xlsx
global join_df
fp = filedialog.askopenfilename(title=u'Please select the side tables')
print(fp)
try:
if fp is not None and len(fp) > 0:
if fp.split('.')[-1] not in ['xls', 'xlsx']:
tk.messagebox.showerror('error', '请选择xls/xlsx的文件')
return
aux_xlsx = fp
lb2['text'] = fp
join_df = None
print('aux_xlsx: ', aux_xlsx)
lb5['text'] = 'No hint'
# tk.messagebox.showinfo('success', '选择原始目录成功')
else:
tk.messagebox.showerror('error', 'Please select the side tables failed')
except:
tk.messagebox.showerror('error', 'Please select the side tables failed')
print(traceback.format_exc())
# Delete the drop-down box and create a new
def destroy_and_new_one(values):
global COMBOPICKER1
global window
COMBOPICKER1.destroy()
COMBOPICKER1 = Combopicker(window, values=values, entrywidth=50)
COMBOPICKER1.place(x=100, y=160)
def join_xlsx():
global COMBOPICKER1
global join_df
if main_xlsx == '' or aux_xlsx == '':
tk.messagebox.showerror('error', 'Please select the main table and side tables')
return
main_df = pd.read_excel(main_xlsx)
aux_df = pd.read_excel(aux_xlsx)
main_df_cols = main_df.columns
aux_df_cols = aux_df.columns
print('main_df_cols: ', main_df_cols)
print('aux_df_cols: ', aux_df_cols)
join_cols_set = set(main_df_cols) & set(aux_df_cols)
# 主键, I directly to the same field name here(列名)作为主键了
key_cols = [item for item in main_df_cols if item in join_cols_set]
print('key_cols: ', key_cols)
union_cols = [item for item in main_df_cols]
# Add schedule other columns
for item in aux_df_cols:
if item not in union_cols:
union_cols.append(item)
print('union_cols: ', union_cols)
join_df = pd.merge(main_df, aux_df, on=key_cols, how='left')
print('join_df:\n', join_df)
destroy_and_new_one(union_cols)
lb5['text'] = 'No hint'
def save_a_excel(save_df):
fp = filedialog.asksaveasfilename(defaultextension='合并后的文件',filetypes=[("excel文件", ".xlsx")])
print(fp)
try:
if fp is not None and len(fp) > 0:
if fp.split('.')[-1] not in ['xls', 'xlsx']:
tk.messagebox.showerror('error', '请保存为xls/xlsx格式的文件')
return
save_df.to_excel(fp, index=False,header=True)
# tk.messagebox.showinfo('success', '选择原始目录成功')
else:
tk.messagebox.showerror('error', 'Save merge table failed')
except:
tk.messagebox.showerror('error', 'Save merge table failed')
print(traceback.format_exc())
def save_xlsx():
global join_df
if main_xlsx == '' or aux_xlsx == '':
tk.messagebox.showerror('error', 'Please select the main table and side tables')
return
if join_df is None:
tk.messagebox.showerror('error', 'Please click on the combined form button')
return
choose_items = COMBOPICKER1.get()
print(choose_items)
if len(choose_items) == 0:
tk.messagebox.showerror('error', 'Please choose to export the column name')
return
else:
choose_items = choose_items.split(',')
union_cols = join_df.columns
save_cols = [item for item in union_cols if item in choose_items]
print('导出列: ', save_cols)
lb5['text'] = '导出列: ' + ' '.join(save_cols)
save_df = join_df[save_cols]
print(save_df)
save_a_excel(save_df)
if __name__ == "__main__":
window = Tk()
# 标题
window.title('合并XLSX小软件')
window.geometry("500x300")
# 不允许重新设置大小
window.resizable('true', 'true')
bt1 = tk.Button(window, text='Select the main table', width=12, height=1, font=tf.Font(size=12), command=select_main_xlsx)
bt1.place(x=60, y=24)
bt2 = tk.Button(window, text='Select the side tables', width=12, height=1, font=tf.Font(size=12), command=select_aux_xlsx)
bt2.place(x=220, y=24)
lb1 = tk.Label(window, text='Did not select the main table', font=tf.Font(size=10))
lb1.place(x=10, y=68)
lb2 = tk.Label(window, text='Did not choose the side tables', font=tf.Font(size=10))
lb2.place(x=10, y=90)
bt3 = tk.Button(window, text='合并表格', width=18, height=1, font=tf.Font(size=12), command=join_xlsx)
bt3.place(x=120, y=120)
lb4 = tk.Label(window, text='导出字段:', font=tf.Font(size=10))
lb4.place(x=10, y=160)
COMBOPICKER1 = Combopicker(window, values=['Please read the form', '读取表格'], entrywidth=50)
# COMBOPICKER1.pack(anchor="w")
COMBOPICKER1.place(x=100, y=160)
bt4 = tk.Button(window, text='Export the combined form', width=18, height=1, font=tf.Font(size=12), command=save_xlsx)
bt4.place(x=120, y=200)
lb5 = tk.Label(window, text='No hint', font=tf.Font(size=10))
lb5.place(x=10, y=240)
window.mainloop()
ComBoPicker.py
''' 引用自https://blog.csdn.net/weixin_45774074/article/details/123293411 自定义多选下拉列表 '''
import tkinter.font as tkFont
import tkinter.ttk as ttk
from tkinter import *
class Picker(ttk.Frame):
def __init__(self, master=None,activebackground='#b1dcfb',values=[],entry_wid=None,activeforeground='black', selectbackground='#003eff', selectforeground='white', command=None, borderwidth=1, relief="solid"):
self._selected_item = None
self._values = values
self._entry_wid = entry_wid
self._sel_bg = selectbackground
self._sel_fg = selectforeground
self._act_bg = activebackground
self._act_fg = activeforeground
self._command = command
ttk.Frame.__init__(self, master, borderwidth=borderwidth, relief=relief)
self.bind("<FocusIn>", lambda event:self.event_generate('<<PickerFocusIn>>'))
self.bind("<FocusOut>", lambda event:self.event_generate('<<PickerFocusOut>>'))
self._font = tkFont.Font()
self.dict_checkbutton = {
}
self.dict_checkbutton_var = {
}
self.dict_intvar_item = {
}
for index,item in enumerate(self._values):
self.dict_intvar_item[item] = IntVar()
self.dict_checkbutton[item] = ttk.Checkbutton(self, text = item, variable=self.dict_intvar_item[item],command=lambda ITEM = item:self._command(ITEM))
self.dict_checkbutton[item].grid(row=index, column=0, sticky=NSEW)
self.dict_intvar_item[item].set(0)
class Combopicker(ttk.Entry, Picker):
def __init__(self, master, values= [] ,entryvar=None, entrywidth=None, entrystyle=None, onselect=None,activebackground='#b1dcfb', activeforeground='black', selectbackground='#003eff', selectforeground='white', borderwidth=1, relief="solid"):
self.values=values
if entryvar is not None:
self.entry_var = entryvar
else:
self.entry_var = StringVar()
entry_config = {
}
if entrywidth is not None:
entry_config["width"] = entrywidth
if entrystyle is not None:
entry_config["style"] = entrystyle
ttk.Entry.__init__(self, master, textvariable=self.entry_var, **entry_config, state = "readonly")
self._is_menuoptions_visible = False
self.picker_frame = Picker(self.winfo_toplevel(), values=values,entry_wid = self.entry_var,activebackground=activebackground, activeforeground=activeforeground, selectbackground=selectbackground, selectforeground=selectforeground, command=self._on_selected_check)
self.bind_all("<1>", self._on_click, "+")
self.bind("<Escape>", lambda event: self.hide_picker())
@property
def current_value(self):
try:
value = self.entry_var.get()
return value
except ValueError:
return None
@current_value.setter
def current_value(self, INDEX):
self.entry_var.set(self.values.index(INDEX))
def _on_selected_check(self, SELECTED):
value = []
if self.entry_var.get() != "" and self.entry_var.get() != None:
temp_value = self.entry_var.get()
value = temp_value.split(",")
if str(SELECTED) in value:
value.remove(str(SELECTED))
else:
value.append(str(SELECTED))
value.sort()
temp_value = ""
for index,item in enumerate(value):
if item!= "":
if index != 0:
temp_value += ","
temp_value += str(item)
self.entry_var.set(temp_value)
def _on_click(self, event):
str_widget = str(event.widget)
if str_widget == str(self):
if not self._is_menuoptions_visible:
self.show_picker()
else:
if not str_widget.startswith(str(self.picker_frame)) and self._is_menuoptions_visible:
self.hide_picker()
def show_picker(self):
if not self._is_menuoptions_visible:
self.picker_frame.place(in_=self, relx=0, rely=1, relwidth=1 )
self.picker_frame.lift()
self._is_menuoptions_visible = True
def hide_picker(self):
if self._is_menuoptions_visible:
self.picker_frame.place_forget()
self._is_menuoptions_visible = False
边栏推荐
- FastCorrect:语音识别快速纠错模型丨RTC Dev Meetup
- Rasa 3.x 学习系列- Rasa - Issues 4792 socket debug logs clog up debug feed学习笔记
- Apache Doris 1.1 特性揭秘:Flink 实时写入如何兼顾高吞吐和低延时
- qt静态编译出现Project ERROR: Library ‘odbc‘ is not defined
- C语言函数详解(2)【函数参数——实际参数(实参)&形式参数(形参)】
- CAS:1445723-73-8,DSPE-PEG-NHS,磷脂-聚乙二醇-活性酯两亲性脂质PEG共轭物
- GameStop NFT 市场分析
- MySql查询某个时间段内的数据(前一周、前三个月、前一年等)
- Test | ali internship 90 days in life: from the perspective of interns, talk about personal growth
- 基于飞腾平台的嵌入式解决方案案例集 1.0 正式发布!
猜你喜欢

vant-swipe自适应图片高度+图片预览

ROS2初级知识(9):bag记录过程数据和重放

1 - vector R language self-study

一个很少见但很有用的SQL功能

Jmeter二次开发实现rsa加密

2022第十一届财经峰会:优炫软件斩获双项大奖

No-code development platform form styling steps introductory course

MySQL 与InnoDB 下的锁做朋友 (四)行锁/记录锁

Jmeter secondary development to realize rsa encryption

了解 NFT 质押:Web3 中赚取被动收益的另一种方式
随机推荐
threejs dynamically adjust the camera position so that the camera can see the object exactly
2022中国眼博会,山东眼健康展,视力矫正仪器展,护眼产品展
Week 7 CNN Architectures - LeNet-5、AlexNet、VGGNet、GoogLeNet、ResNet
创建型模式 - 简单工厂模式StaticFactoryMethod
执子手,到永恒
分库分表索引设计:二级索引、全局索引的最佳设计实践
「X」to「Earn」:赛道现状与破局思路
Cholesterol-PEG-Acid,胆固醇-聚乙二醇-羧基保持在干燥、低温环境下
MySql查询某个时间段内的数据(前一周、前三个月、前一年等)
科研用Cholesterol-PEG-NHS,NHS-PEG-CLS,胆固醇-聚乙二醇-活性酯
VMware workstation 程序启动慢
Rasa 3.x 学习系列- Rasa - Issues 4792 socket debug logs clog up debug feed学习笔记
Cholesterol-PEG-Amine,CLS-PEG-NH2,胆固醇-聚乙二醇-氨基脂两亲性脂质衍生物
脂溶性胆固醇-聚乙二醇-叠氮,Cholesterol-PEG-Azide,CLS-PEG-N3
d合并json
Test | ali internship 90 days in life: from the perspective of interns, talk about personal growth
令人心动的AI综述(1)
Mock工具之Moco使用教程
基于STM32的FLASH读写实验含代码(HAL库)
华为设备配置BFD与接口联动(触发与BFD联动的接口物理状态变为Down)