引言
最近,经常抽查excel表中的一些行,到一个新表中;于是想着写一个程序,自动完成。
功能
基础功能
- 从原表中随机抽取n行,到一个新表中(可用于老师抽查学生作业,领导抽查核酸(坏笑.jpg))
- 抽取某行后,将原表中该行背景填充为黄色。每次抽查时,首先判断当前行是否为黄色,若不是,则抽查;若是,则换成下一行;保证了多次抽查,没有重复名单。
基础功能简单,适用于普通用户或者急于使用的用户。只需要原表的路径
(注意:是绝对路径,如C:\Users\admin\Desktop\2.xlsx),和要抽取的行数
即可,抽取后生成的新表,将会保存在和软件统一目录下。
软件界面如下
点击确定后,显示导出成功。
然后,在和软件相同的目录下,找抽查.xlsx
,打开即可。
软件下载地址
链接:https://pan.baidu.com/s/1TCePlzptsMwqrCKFT7CVGA
提取码:zjoy
拓展功能
代码基本框架已经给出,懂代码的朋友,根据需求酌情修改即可。
如可以实现,多个工作簿的读取,给行填充不同的颜色,随机抽查的算法根据使用场景酌情改进等等。
代码写的有些仓促,有不足或者可以改进的地方,欢迎各位同仁讨论交流。
源码已经给出。
源码
from openpyxl import load_workbook, Workbook
from openpyxl.styles import PatternFill
import random
import sys
import os
import tkinter as tk
import tkinter.messagebox# 黄色 FFFFFF00
# 粉色 ffc7ce# 生成随机数,并排序
def gen_random(l, r, cnt):a = []a = random.sample(range(l, r + 1), cnt)a.sort()return a# 随机选取学生的函数, 可以在进一部优化
def gen_random_students(l, r, cnt):print(cnt)a = random.sample(range(l, (int)(r / 2)), (int)(cnt / 2))b = random.sample(range((int)(r / 2), r), cnt - (int)(cnt / 2))c = a + bc.sort()print("生成的随机数:")print(c)return cdef new_excel(filename, first_row):a = Workbook()# 获取当前活跃的工作薄ws = a.activews.title = "Sheet1"# 插入第一行标题ws.append(first_row)a.save(filename=filename)return adef deal(excel_path, sheet_name, cnt, col_l, col_r, wb2):""":param excel_path: excel的绝对路径:param sheet_name: 工作表名称:param cnt: 抽查人数:param col_l: 从第几列开始取:param col_r: 到第几列结束:param wb2: 要保存的新表:return:"""# 保存路径new_excel_path = os.path.dirname(os.path.realpath(sys.argv[0]))# 默认可读写,若有需要可以指定write_only和read_only为Truewb = load_workbook(excel_path)# 根据sheet名字获得sheetsheet1 = wb[sheet_name]# 获得最大列和最大行max_row = sheet1.max_rowmax_col = sheet1.max_columnprint("行数max_row: " + str(max_row))if col_r == -1:col_r = max_colif wb2 == None:wb2 = Workbook()ws = wb2.activews.title = "Sheet1"wb2.save(new_excel_path + "\\" + "抽查.xlsx")# 生成随机数,并排序res = gen_random_students(2, max_row, cnt)# 设置颜色填充,FFFFFF00为填充黄色标准色:00000000yellow_fill = PatternFill(fill_type="solid", fgColor="FFFFFF00")# 因为按行,所以返回A1, B1, C1这样的顺序k = 0for i, row in zip(range(1, max_row + 1), sheet1.rows):if i == res[k]:# 本行不合法,换下一行抽if str(row[0].value) == "None" or str(sheet1.cell(row=i, column=1).fill.fgColor.rgb) == "FFFFFF00":print(str(i) + "行不合法 " + str(str(row[0].value)) + " --->换下一行处理")res[k] += 1continueprint("i: " + str(i), end=" ")print("抽查序号 : " + str(k + 1))k += 1# 本行不为空,且未被抽过list1 = []print(str(i), end=" ")for j, cell in zip(range(col_l, col_r + 1), row):# 当前单元格填充为黄色sheet1.cell(row=i, column=j).fill = yellow_filllist1.append(str(cell.value))print(str(cell.value), end=" ")print("")# 添加抽到的行,到新表中wb2['Sheet1'].append(list1)if k == cnt:break# 保证当遇到抽取的两个数非常近,且之前都被选中的情况res[k] = i + 1 if res[k] <= i else res[k]# 此处待优化解决if k < cnt:print("!!!!未抽查够人数")# 保存修改wb.save(excel_path)wb2.save(new_excel_path + "\\" + "抽查.xlsx")tk.messagebox.showinfo('提示', '导出完成!')passdef start1(excel_path, check_cnt):print(excel_path)print(check_cnt)deal(excel_path, "Sheet1", int(check_cnt), 1, -1, None)# 启动程序
def set_up():window = tk.Tk()window.geometry('500x540+1000+500')window.title('excel 随机抽查行')# 软件介绍label_txt = "本软件旨在随机从excel表中随机抽取部分行到\n新表中,并将已抽取的行填空为黄色,下次不再抽取,\n保证抽出的行是不重复的,直至全部抽查完。\n 结果保存该软件所在位置,名为“抽查.xlsx”"label0 = tk.Label(window, text=label_txt, bg='yellow', font=('KaiTi', 15), justify="left")# 原表路径和输入文本框label1 = tkinter.Label(window, text="原表路径", bg="LightSkyBlue", font=('KaiTi', 20))txt1 = tk.StringVar()t1 = tk.Entry(window, font=20, textvariable=txt1, width=30, state='normal', selectforeground="red")# # 选取表中的,工作薄sheet名称# label2 = tkinter.Label(window, text="sheet名称", bg="pink", font=('KaiTi', 20))# txt2 = tk.StringVar()# t2 = tk.Entry(window, font=20, textvariable=txt2, width=30, state='normal', selectforeground="red")# 要抽查的人数label3 = tkinter.Label(window, text="抽查人数", bg="LightSkyBlue", font=('KaiTi', 20))txt3 = tk.StringVar()t3 = tk.Entry(window, font=20, textvariable=txt3, width=30, state='normal', selectforeground="red")# # 抽查导入新表的名称;若为空时,在当前路径下,新建一个表# label4 = tkinter.Label(window, text="新表路径", bg="pink", font=('KaiTi', 20))# txt4 = tk.StringVar()# t4 = tk.Entry(window, font=20, textvariable=txt4, width=30, state='normal', selectforeground="red")ok = tk.Button(window, text='确定', width=30, bg="violet", command=lambda: start1(txt1.get(), txt3.get()))# 声明label5 = tkinter.Label(window, text="声明:该软件仅供学习使用,\n不得用于任何商业用途", bg="red", font=('KaiTi', 15))# ps:label5 = tkinter.Label(window, text="为了方便大部分用户使用,该软件仅封装了一个简单\n的抽取功能;其实许多复杂地抽取,均可\n以该软件为基础改进,实现定制化抽取。\n代码已开源,欢迎交流。",bg="pink", font=('KaiTi', 12))# 以下内容为各个组件的排版label0.grid(ipadx=10, ipady=10, row=0, columnspan=2)label1.grid(ipadx=10, padx=10, pady=10, row=1, column=0)t1.grid(ipadx=10, ipady=10, pady=10, row=1, column=1)# label2.grid(ipadx=10, padx=10, pady=10, row=2, column=0)# t2.grid(ipadx=10, ipady=10, pady=10, row=2, column=1)label3.grid(ipadx=10, padx=10, pady=10, row=3, column=0)t3.grid(ipadx=10, ipady=10, pady=10, row=3, column=1)# label4.grid(ipadx=10, padx=10, pady=10, row=4, column=0)# t4.grid(ipadx=10, ipady=10, pady=10, row=4, column=1)ok.grid(ipadx=10, ipady=5, pady=10, row=5, columnspan=2)label5.grid(ipadx=10, padx=10, pady=30, row=6, columnspan=2)window.mainloop()pass# 启动程序
set_up()