最近,经常抽查excel表中的一些行,到一个新表中;于是想着写一个程序,自动完成。
基础功能简单,适用于普通用户或者急于使用的用户。只需要原表的路径
(注意:是绝对路径,如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 + b
c.sort()
print("生成的随机数:")
print(c)
return c
def new_excel(filename, first_row):
a = Workbook()
# 获取当前活跃的工作薄
ws = a.active
ws.title = "Sheet1"
# 插入第一行标题
ws.append(first_row)
a.save(filename=filename)
return a
def 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为True
wb = load_workbook(excel_path)
# 根据sheet名字获得sheet
sheet1 = wb[sheet_name]
# 获得最大列和最大行
max_row = sheet1.max_row
max_col = sheet1.max_column
print("行数max_row: " + str(max_row))
if col_r == -1:
col_r = max_col
if wb2 == None:
wb2 = Workbook()
ws = wb2.active
ws.title = "Sheet1"
wb2.save(new_excel_path + "\\" + "抽查.xlsx")
# 生成随机数,并排序
res = gen_random_students(2, max_row, cnt)
# 设置颜色填充,FFFFFF00为填充黄色标准色:00000000
yellow_fill = PatternFill(fill_type="solid", fgColor="FFFFFF00")
# 因为按行,所以返回A1, B1, C1这样的顺序
k = 0
for 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] += 1
continue
print("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_fill
list1.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('提示', '导出完成!')
pass
def 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()