From 01909ed49fa1309ebdea7705752fe3f73b5e3f74 Mon Sep 17 00:00:00 2001 From: wangdan Date: Mon, 29 Nov 2021 18:19:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compare.py | 136 +++++++++++++++++++++ rowspan_alignment.py | 279 +++++++++++++++++++++++++++++++++++++++++++ workbooks_merge.py | 224 ++++++++++++++++++++++++++++++++++ 3 files changed, 639 insertions(+) create mode 100644 compare.py create mode 100644 rowspan_alignment.py create mode 100644 workbooks_merge.py diff --git a/compare.py b/compare.py new file mode 100644 index 0000000..2dc142b --- /dev/null +++ b/compare.py @@ -0,0 +1,136 @@ +# -*- coding:utf-8 -*- +################################ +# excel 表格对比 +# +################################ +import os +import tkinter as tk +from tkinter import ttk +from tkinter import filedialog, dialog + + +class CompareData: + pass + + +class CompareFormat: + pass + + +class MainView: + def __init__(self, root: tk.Frame): + self.__root: tk.Frame = root + + self.__select_template_file_mess: tk.StringVar = tk.StringVar() + self.__select_template_file_mess.set('请选择模版文件') + self.__template_file_name: tk.StringVar = tk.StringVar() + self.__template_file_name.set('') + + self.__select_compare_file_mess: tk.StringVar = tk.StringVar() + self.__select_compare_file_mess.set('请选择对比文件') + self.__compare_file_name: tk.StringVar = tk.StringVar() + self.__compare_file_name.set('') + + self.__conf_type: tk.IntVar = tk.IntVar() # 配置方式 + + self.__progress: tk.IntVar = tk.IntVar() + self.__progress.set(20) + + def create_windows(self): + template_f = tk.Frame(self.__root, bg='gainsboro') + template_f.rowconfigure(0, weight=1) + template_f.columnconfigure(0, weight=1) + template_f.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NW) + + compare_f = tk.Frame(self.__root, bg='gainsboro') + compare_f.rowconfigure(0, weight=1) + compare_f.columnconfigure(0, weight=1) + compare_f.grid(row=1, column=0, padx=5, pady=5, sticky=tk.NW) + + compare_type_f = tk.Frame(self.__root, bd=1, height=50) + compare_type_f.grid(row=2, column=0, padx=5, pady=5, sticky=tk.NW) + + start_f = tk.Frame(self.__root, bd=1, height=50) + start_f.grid(row=3, column=0, padx=5, pady=5, sticky=tk.NW) + + scala_f = tk.Frame(self.__root, bd=1, height=50) + scala_f.grid(row=4, column=0, padx=5, pady=5, sticky=tk.NW) + + info_f = tk.Label(self.__root, bg='silver', text='自动判断列名并合并相同列数据') + info_f.grid(row=5, column=0, sticky=tk.NSEW) + + template_f_select = ttk.Button(template_f, state=tk.NORMAL, text="选择模版文件", command=self.__select_template_file) + template_f_select.grid(row=0, column=0) + template_f_text = ttk.Label(template_f, textvariable=self.__select_template_file_mess) + template_f_text.grid(row=0, column=1) + + compare_f_select = ttk.Button(compare_f, text="选择对比文件", command=self.__select_compare_file) + compare_f_select.grid(row=0, column=0) + compare_f_text = ttk.Label(compare_f, textvariable=self.__select_compare_file_mess) + compare_f_text.grid(row=0, column=1) + + data_only_rb = ttk.Radiobutton(compare_type_f, variable=self.__conf_type, text='仅对比数据', value=0, + command=self.__conf_type_selection) + data_only_rb.grid(row=0, column=0, padx=5, sticky=tk.W) + format_only_rb = ttk.Radiobutton(compare_type_f, variable=self.__conf_type, text='仅对比格式', value=1, + command=self.__conf_type_selection) + format_only_rb.grid(row=0, column=1, padx=5, sticky=tk.W) + + data_format_rb = ttk.Radiobutton(compare_type_f, variable=self.__conf_type, text='对比数据和格式', value=2, + command=self.__conf_type_selection) + data_format_rb.grid(row=0, column=2, padx=5, sticky=tk.W) + + start_b = ttk.Button(start_f, state=tk.NORMAL, text="开始", command=self.__start_compare) + start_b.grid(row=0, column=0) + + progressbar = ttk.Progressbar(scala_f, length=200, mode="determinate", orient=tk.HORIZONTAL, + variable=self.__progress) + progressbar.grid(row=0, column=0, padx=5, sticky=tk.NSEW) + + def __select_template_file(self): + file = filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser('~/')), + filetypes=[('Excel xls', '*.xls')]) + if len(file) > 0: + self.__select_template_file_mess.set('模版文件:' + file) + else: + self.__select_template_file_mess.set('请选择模版文件') + self.__template_file_name.set(file) + + def __select_compare_file(self): + file = filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser('~/')), + filetypes=[('Excel xls', '*.xls')]) + if len(file) > 0: + self.__select_compare_file_mess.set('对比文件:' + file) + else: + self.__select_compare_file_mess.set('请选择对比文件') + self.__compare_file_name.set(file) + + def __conf_type_selection(self): + conf_type = self.__conf_type.get() + if conf_type == 0: + pass + elif conf_type == 1: + pass + elif conf_type == 2: + pass + + def __start_compare(self): + pass + + +def main(): + root = tk.Tk() + root.title('Excel 文件对比工具') + root.geometry('720x640') + root.minsize(720, 640) + root.rowconfigure(0, weight=1) + root.columnconfigure(0, weight=1) + master_frame = tk.Frame(root) + master_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW) + w = MainView(master_frame) + w.create_windows() + root.mainloop() + + +if __name__ == '__main__': + main() diff --git a/rowspan_alignment.py b/rowspan_alignment.py new file mode 100644 index 0000000..529fe3e --- /dev/null +++ b/rowspan_alignment.py @@ -0,0 +1,279 @@ +# -*- coding:utf-8 -*- +################################ +# excel 表格分级下沉填充 +# 任意一个 1 级列的值发生变化,则 2级列停止下沉, +# 同理 任意一个 2级列的值发生了变化时, 3级列停止下沉,以此类推 +# +# +# +################################ +import os +import sys + +import xlrd +import xlwt +from xlutils.copy import copy +import tkinter as tk +from tkinter import filedialog, dialog +import tkinter.messagebox +from tkinter import ttk + +file_path = '' +output_file_path = '' +config_str = '' + +window = tk.Tk() +root = tk.Frame(window) +root.pack() + +progress_scale = tk.Scale() +message_label = tk.Label() + +file_path_tk_var = tk.StringVar() +file_path_tk_var.set('点击上面按钮选择文件') + +out_file_path_tk_var = tk.StringVar() +out_file_path_tk_var.set('点击上面按钮设置保存位置') + +message_tk_var = tk.StringVar() +message_tk_var.set("请选择文件并填写处理规则") + +progress = tk.IntVar() +progress.set(0) + + +def create_file(file_name): + workbook = xlwt.Workbook() # 新建一个工作簿 + sheet = workbook.add_sheet('Sheet1') + sheet.write(0, 0, None) + workbook.save(file_name) + + +def append_write(rows, file_name): + global message_label + message_tk_var.set("正在保存,请稍后...") + message_label.update() + index = len(rows) + workbook = xlrd.open_workbook(file_name) + sheets = workbook.sheet_names() + worksheet = workbook.sheet_by_name(sheets[0]) + rows_old = worksheet.nrows + new_workbook = copy(workbook) + new_worksheet = new_workbook.get_sheet(0) + for i in range(0, index): + for j in range(0, len(rows[i])): + new_worksheet.write(i + rows_old, j, rows[i][j]) + new_workbook.save(file_name) # 保存工作簿 + print("xls格式表格【追加】写入数据成功!") + + +def main(): + global output_file_path + global file_path + global config_str + global progress + global message_label + create_file(output_file_path) + wb = xlrd.open_workbook(file_path) + st = wb.sheet_by_index(0) + title = st.row_values(0) + append_write([title], output_file_path) + message_tk_var.set("正在处理数据,请稍后...") + message_label.update() + batch_row = [] + tmp_row = [None for _ in range(len(title))] + num_config = config_format() + tmp_array = [None for _ in range(len(num_config))] # [ {A = 1,B = 2},{I = 78},{K = 'ldk'} ] + for i in range(1, st.nrows): + row_v = st.row_values(i) + for step in range(0, len(num_config)): # 先检查缓存是否需要改变 + cell = row_v[num_config[step][0]] + if (not (cell is None)) & (len(str(cell)) > 0): + for del_i in range(step, len(num_config)): + tmp_array[del_i] = None + new_dic = {} + for column_num in num_config[step]: + new_dic[column_num] = row_v[column_num] + tmp_array[step] = new_dic + tmp_row = [None for _ in range(len(title))] + for ci in range(0, len(row_v)): + tmp_row[ci] = row_v[ci] + for step in tmp_array: + if step is None: + continue + for k in step.keys(): + tmp_row[k] = step[k] + batch_row.append(tmp_row) + if (len(batch_row) >= 100000) | (i == st.nrows - 1): + append_write(batch_row, output_file_path) + batch_row = [] + message_tk_var.set("正在处理数据,请稍后...") + message_label.update() + if i % 100 == 0: + progress.set(i / st.nrows * 100) + global progress_scale + progress_scale.update() + tk.messagebox.showinfo(title='处理完成', message='文件保存至\n' + output_file_path) + progress.set(0) + message_tk_var.set("处理完成") + message_label.update() + + +def config_format(): + global config_str + config_array = [] + for line in config_str.split('\n'): + if len(line.replace(' ', '')) == 0: + continue + step_array = [] + for column_str in line.split(','): + column_str = column_str.replace(' ', '') + if len(column_str) == 0: + continue + step_array.append(column_str) + if len(step_array) > 0: + config_array.append(step_array) + num_config = [] + for step in config_array: + num_step = [] + for column_name in step: + if len(column_name) == 1: + col = ord(column_name.upper()) - ord('A') + 1 + num_step.append(col - 1) + # 输入为AA2类型 + elif len(column_name) == 2: + col_1 = ord(column_name[0].upper()) - ord('A') + 1 + col_2 = ord(column_name[1].upper()) - ord('A') + 1 + col = col_1 * 26 + col_2 + num_step.append(col - 1) + num_config.append(num_step) + return num_config + + +def open_file(): + global file_path + file_path = filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser('~/')), + filetypes=[('Excel xls', '*.xls')]) + if len(file_path) > 0: + file_path_tk_var.set(file_path) + + +def save_file(): + global output_file_path + output_file_path = filedialog.asksaveasfilename(title=u'保存文件') + if len(output_file_path) > 0: + if not str(output_file_path).endswith('.xls'): + output_file_path = output_file_path + '.xls' + out_file_path_tk_var.set(output_file_path) + + +if __name__ == '__main__': + window.title('Excel 指定列下沉填充') + window.geometry('800x600') + window.minsize(500, 300) + + + def info(): + info = """ + excel 表格分级下沉填充 + 任意一个 1 级列的值发生变化,则 2级列停止下沉, + 同理 任意一个 2级列的值发生了变化时, 3级列停止下沉,以此类推 + + 规则填写方法: + 在文本框中,每一行代表一个等级:如第一行代表等级1,第二行代表等级2,以此类推 + 每一行中填写需要下沉填充的列号,用逗号隔开,如 : A,B,C,F,AE,AF + + 如,原表格结构: + -------------------------------------- + A B C D E + 1 100 + 2 45 89 + 3 iy qq + 4 ip ui + -------------------------------------- + + 使用规则 + ----------------------- + A + B,C + ----------------------- + + 填充后的结果是: + -------------------------------------- + A B C D E + 1 100 + 2 100 45 89 + 3 100 45 89 iy qq + 4 100 45 89 ip ui + -------------------------------------- + """ + tk.messagebox.showinfo(title='使用说明', message=info) + + + bt0 = ttk.Button(root, text='使用说明', command=info) + bt0.pack() + + bt1 = ttk.Button(root, text='打开文件', width=15, command=open_file) + bt1.pack() + file_path_label = tk.Label(root, text='', textvariable=file_path_tk_var, bg='grey', font=('Arial', 12)) + file_path_label.pack() + + f1 = ttk.Frame(root) + s1 = ttk.Scrollbar(f1, orient=tk.VERTICAL) + s2 = ttk.Scrollbar(f1, orient=tk.HORIZONTAL) + config_label = ttk.Label(f1, text='请输入需要下沉填充的列:列名用逗号隔开,一行表示一个等级') + config_label.pack() + config_text = tk.Text(f1, width=60, highlightthickness=5, highlightbackground='grey', undo=True, + yscrollcommand=s1.set, + xscrollcommand=s2.set, + wrap=tk.NONE) + s1.pack(side=tk.RIGHT, fill=tk.Y) + s1.config(command=config_text.yview) + s2.pack(side=tk.BOTTOM, fill=tk.X) + s2.config(command=config_text.xview) + config_text.pack() + + f1.pack() + bt2 = ttk.Button(root, text='保存文件', width=15, command=save_file) + bt2.pack() + out_file_path_label = tk.Label(root, text='', textvariable=out_file_path_tk_var, bg='grey', font=('Arial', 12), ) + out_file_path_label.pack() + + + def start(): + + global config_str + if len(str(file_path)) < 1: + tk.messagebox.showwarning(title='未选择文件', message='请点击 "打开文件" 按钮选择需要处理的文件') + return + if len(str(output_file_path)) < 1: + tk.messagebox.showwarning(title='未选择输出文件', message='请点击 "保存文件" 按钮选择输出文件') + return + bt3['state'] = tk.DISABLED + try: + config_str = config_text.get("0.0", "end") + try: + main() + except Exception as e: + message_tk_var.set("执行过程出现错误,请重试") + message_label.update() + print(e) + except Exception as e: + message_tk_var.set("列配置填写错误,请检查") + message_label.update() + print(e) + bt3['state'] = tk.NORMAL + + + bt3 = ttk.Button(root, text='开始处理', command=start) + bt3.pack() + + progress_scale = tk.Scale(root, label='进度', from_=0, to=100, orient=tk.HORIZONTAL, length=200, showvalue=0, + tickinterval=20, + variable=progress) + + message_label = tk.Label(window, text='', textvariable=message_tk_var, bg='yellow', font=('Arial', 12)) + message_label.pack() + + progress_scale.pack() + window.mainloop() diff --git a/workbooks_merge.py b/workbooks_merge.py new file mode 100644 index 0000000..c5a70be --- /dev/null +++ b/workbooks_merge.py @@ -0,0 +1,224 @@ +# -*- coding:utf-8 -*- +################################ +# excel 表格分级下沉填充 +# 任意一个 1 级列的值发生变化,则 2级列停止下沉, +# 同理 任意一个 2级列的值发生了变化时, 3级列停止下沉,以此类推 +# +# +# +################################ +import os +import sys + +import xlrd +import xlwt +from xlutils.copy import copy +import tkinter as tk +from tkinter import filedialog, dialog +import tkinter.messagebox +from tkinter import ttk + + +class MergeWindows(object): + """ 配置项 key """ + INCLUDE_ROW_HEAD = 'include_row_head' + INCLUDE_ROW_TAIL = 'include_row_tail' + INCLUDE_ROW_NAME = 'include_row_name' + INCLUDE_COL_HEAD = 'include_col_head' + INCLUDE_COL_TAIL = 'include_col_tail' + INCLUDE_COL_NAME = 'include_col_name' + EXCLUDE_ROW_HEAD = 'exclude_row_head' + EXCLUDE_ROW_TAIL = 'exclude_row_tail' + EXCLUDE_ROW_NAME = 'exclude_row_name' + EXCLUDE_COL_HEAD = 'exclude_col_head' + EXCLUDE_COL_TAIL = 'exclude_col_tail' + EXCLUDE_COL_NAME = 'exclude_col_name' + + def __init__(self, master: tk.Frame = None): + super().__init__() + self.__master: tk.Frame = master + self.__conf_type: tk.IntVar = tk.IntVar() # 配置方式 + self.__conf_type.set(0) + self.__f_auto_conf: tk.Frame = tk.Frame() + self.__f_handle_conf: tk.Frame = tk.Frame() + + self.__conf_text_widgets: dict[str, tk.Text] = {} + self.__input_files_list: list[str] = [] + self.__output_file: str = None + # 显示变量 + self.__select_files_mess: tk.StringVar = tk.StringVar() + self.__select_files_mess.set('请选择要合并的文件') + self.__output_file_mess: tk.StringVar = tk.StringVar() + self.__output_file_mess.set('选择输出文件') + + def __conf_type_selection(self): + conf_type = self.__conf_type.get() + if conf_type == 0: + self.__f_handle_conf.grid_remove() + self.__f_auto_conf.grid() + elif conf_type == 1: + self.__f_auto_conf.grid_remove() + self.__f_handle_conf.grid() + + def __select_files(self): + file_list = filedialog.askopenfilenames(title=u'选择文件', initialdir=(os.path.expanduser('~/')), + filetypes=[('Excel xls', '*.xls')]) + if len(file_list) != 0: + self.__select_files_mess.set('选中' + str(len(file_list)) + '个文件') + else: + self.__select_files_mess.set('请选择要合并的文件') + self.__input_files_list = file_list + + def __save_file_path(self): + output_file_path = filedialog.asksaveasfilename(title=u'保存文件') + if len(output_file_path) > 0: + if (not str(output_file_path).endswith('.xls')) & (not str(output_file_path).endswith('.xlsx')): + output_file_path = output_file_path + '.xls' + self.__output_file = output_file_path + self.__output_file_mess.set(os.path.split(output_file_path)[1]) + + def __clear_conf(self): + for w_key in self.__conf_text_widgets.keys(): + self.__conf_text_widgets.get(w_key).delete("0.0", "end") + self.__input_files_list = [] + self.__output_file = None + self.__select_files_mess.set('请选择要合并的文件') + self.__output_file_mess.set('选择输出文件') + self.__conf_type.set(0) + + def __start(self): + if self.__conf_type == 0: + pass + elif self.__conf_type == 1: + pass + + def create_windows(self): + self.__widget_row_col_configure(self.__master, {2: 1}, {0: 1}) + """ 顶端功能按钮 """ + f_info = tk.Frame(self.__master, height=50, bd=1, bg='gainsboro') + f_info.grid(row=0, column=0, padx=5, pady=5, ipadx=2, ipady=2, sticky=tk.NSEW) + """ 文件选择栏 """ + f_files = tk.Frame(self.__master, height=100, bd=1, bg='gainsboro') + f_files.grid(row=1, column=0, padx=5, pady=5, sticky=tk.EW) + """ 配置栏 """ + f_config = tk.Frame(self.__master, bd=1, bg='gainsboro') + f_config.grid(row=2, column=0, padx=5, pady=5, sticky=tk.NSEW) + f_config.rowconfigure(1, weight=1) + f_config.columnconfigure(0, weight=1) + """ 顶端功能按钮控件布局 """ + f_info.columnconfigure(0, weight=1) + l_massage = ttk.Label(f_info, text='请选择文件') + l_massage.grid(row=0, column=0, sticky=tk.EW) + b_start = ttk.Button(f_info, text="开始") + b_start.grid(row=0, column=1, padx=5, sticky=tk.E) + b_cancel = ttk.Button(f_info, text="取消") + b_cancel.grid(row=0, column=2, padx=5, sticky=tk.E) + b_reset = ttk.Button(f_info, text="重置", command=self.__clear_conf) + b_reset.grid(row=0, column=3, padx=5, sticky=tk.E) + b_help = ttk.Button(f_info, text="帮助") + b_help.grid(row=0, column=4, padx=5, sticky=tk.E) + """ 文件选择栏控件布局 """ + self.__widget_row_col_configure(f_files, {}, {0: 1, 1: 1}) + + f_input = tk.Frame(f_files, bg='gainsboro') + f_input.grid(row=0, column=0, sticky=tk.NSEW) + f_output = tk.Frame(f_files, bg='gainsboro') + f_output.grid(row=0, column=1, sticky=tk.NSEW) + + b_in_select = ttk.Button(f_input, text="选择要合并的文件", command=self.__select_files) + b_in_select.grid(row=0, column=0) + l_in_select = ttk.Label(f_input, textvariable=self.__select_files_mess) + l_in_select.grid(row=1, column=0) + b_out_select = ttk.Button(f_output, text="选择输出文件", command=self.__save_file_path) + b_out_select.grid(row=0, column=0) + l_out_select = ttk.Label(f_output, textvariable=self.__output_file_mess) + l_out_select.grid(row=1, column=0) + + """ 配置规则控件布局 """ + self.__f_auto_conf = tk.Frame(f_config, bd=1, bg='silver') + self.__f_auto_conf.grid(row=1, column=0, sticky=tk.NSEW) + self.__f_handle_conf = tk.Frame(f_config, bd=1, bg='silver') + self.__f_handle_conf.grid(row=1, column=0, padx=5, pady=5, sticky=tk.NSEW) + self.__widget_row_col_configure(self.__f_handle_conf, {0: 1}, {0: 1, 1: 1}) + self.__f_handle_conf.grid_remove() + + f_config_radio = tk.Frame(f_config, bd=1, height=50, bg='silver') + f_config_radio.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NW) + + r_auto = ttk.Radiobutton(f_config_radio, variable=self.__conf_type, text='自动合并', value=0, + command=self.__conf_type_selection) + r_auto.grid(row=0, column=0, sticky=tk.W) + r_handle = ttk.Radiobutton(f_config_radio, variable=self.__conf_type, text='手动配置', value=1, + command=self.__conf_type_selection) + r_handle.grid(row=0, column=1, sticky=tk.W) + t_auto_info = tk.Label(self.__f_auto_conf, bg='silver', text='自动判断列名并合并相同列数据') + t_auto_info.grid(row=0, column=0, sticky=tk.NSEW) + + # 手动配置框 + f_include_conf = tk.LabelFrame(self.__f_handle_conf, text='包含', padx=5, pady=5, bg='silver') + f_include_conf.grid(row=0, column=0, padx=3, pady=3, sticky=tk.NSEW) + self.__widget_row_col_configure(f_include_conf, {2: 1, 4: 1, 6: 1, 10: 1, 12: 1, 14: 1}, {0: 1}) + + l_include_0 = tk.Label(f_include_conf, text='行设置:(不填写代表包含全部行)', bg='silver') + l_include_0.grid(row=0, column=0, columnspan=2, ) + self.__create_text(f_include_conf, self.INCLUDE_ROW_HEAD, '正数第N行', 1, 0) + self.__create_text(f_include_conf, self.INCLUDE_ROW_TAIL, '倒数第N行', 3, 0) + self.__create_text(f_include_conf, self.INCLUDE_ROW_NAME, '行名(取第一列数据作为行名)', 5, 0) + sep_0 = ttk.Separator(f_include_conf, orient='horizontal') + sep_0.grid(row=7, column=0, columnspan=2, padx=5, pady=5, sticky=tk.EW) + l_include_3 = tk.Label(f_include_conf, text='列设置:(不填写代表包含全部列)', bg='silver') + l_include_3.grid(row=8, column=0, columnspan=2) + self.__create_text(f_include_conf, self.INCLUDE_COL_HEAD, '正数第N列', 9, 0) + self.__create_text(f_include_conf, self.INCLUDE_COL_TAIL, '倒数第N列', 11, 0) + self.__create_text(f_include_conf, self.INCLUDE_COL_NAME, '列名(取第一行数据作为列名)', 13, 0) + + f_exclude_conf = tk.LabelFrame(self.__f_handle_conf, text='不包含', padx=5, pady=5, bg='silver') + f_exclude_conf.grid(row=0, column=1, padx=3, pady=3, sticky=tk.NSEW) + self.__widget_row_col_configure(f_exclude_conf, {2: 1, 4: 1, 6: 1, 10: 1, 12: 1, 14: 1}, {0: 1}) + l_exclude_0 = tk.Label(f_exclude_conf, text='行设置:(不填写代表没有需要排除的行)', bg='silver') + l_exclude_0.grid(row=0, column=0, columnspan=2) + self.__create_text(f_exclude_conf, self.EXCLUDE_ROW_HEAD, '正数第N行', 1, 0) + self.__create_text(f_exclude_conf, self.EXCLUDE_ROW_TAIL, '倒数第N行', 3, 0) + self.__create_text(f_exclude_conf, self.EXCLUDE_ROW_NAME, '行名(取第一列数据作为行名)', 5, 0) + + sep_1 = ttk.Separator(f_exclude_conf, orient='horizontal') + sep_1.grid(row=7, column=0, columnspan=2, padx=5, pady=5, sticky=tk.EW) + l_exclude_3 = tk.Label(f_exclude_conf, text='列设置:(不填写代表没有需要排除的列)', bg='silver') + l_exclude_3.grid(row=8, column=0, columnspan=2) + self.__create_text(f_exclude_conf, self.EXCLUDE_COL_HEAD, '正数第N列', 9, 0) + self.__create_text(f_exclude_conf, self.EXCLUDE_COL_TAIL, '倒数第N列', 11, 0) + self.__create_text(f_exclude_conf, self.EXCLUDE_COL_NAME, '列名(取第一行数据作为列名)', 13, 0) + + def __widget_row_col_configure(self, root: tk.Widget, rows: dict[int, int], columns: dict[int, int]): + for row in rows.keys(): + root.rowconfigure(row, weight=rows[row]) + for col in columns.keys(): + root.columnconfigure(col, weight=columns[col]) + + def __create_text(self, root: tk.Widget, name: str, label_text: str, r: int, c: int): + label = tk.Label(root, text=label_text, bg='silver') + label.grid(row=r, column=c, columnspan=2, sticky=tk.W) + scroll_y = ttk.Scrollbar(root, orient=tk.VERTICAL) + text = tk.Text(root, yscrollcommand=scroll_y.set, undo=True, wrap=tk.NONE) + text.grid(row=r + 1, column=c, sticky=tk.NSEW) + scroll_y.grid(row=r + 1, column=c + 1, ) + scroll_y.config(command=text.yview) + self.__conf_text_widgets[name] = text + + +def main(): + root = tk.Tk() + root.title('Excel 文件合并工具') + root.geometry('720x640') + root.minsize(720, 640) + root.rowconfigure(0, weight=1) + root.columnconfigure(0, weight=1) + master_frame = tk.Frame(root) + master_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW) + w = MergeWindows(master_frame) + w.create_windows() + root.mainloop() + + +if __name__ == '__main__': + main()