前言
随机抽取软件可以在各种应用场景中发挥作用。
随机抽取器常见的应用场景有以下:
- 抽奖活动:在各种抽奖活动中,例如公司年会、促销活动或社交媒体抽奖,随机抽取软件可以帮助你从参与者中随机选取获奖者。
- 研究实验:在科学研究中,研究者可能需要随机选择样本或实验条件,以确保实验结果的可靠性和代表性。
- 民意调查:在进行民意调查时,你可能需要从大量受访者中随机选择一部分人来参与调查,以获得更具代表性的结果。
- 随机分组:在实验设计、医学研究或教育研究中,研究者可能需要将被试对象随机分配到不同的处理组或对照组,以便比较不同组之间的差异。
- 游戏和竞赛:在游戏、竞赛或体育比赛中,随机抽取软件可以用于分配参与者的顺序、对手或队伍,以保证公平性。
- 教学活动:在课堂上,教师可以使用随机抽取软件来选择回答问题的学生,以增加参与度和公平性。
工具界面
代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName : randomPickerApp.py
# @Time : 2024/2/19 9:04
# @Author : Marst.Zhang
"""
task:
output:
应用场景:
"""
import functools
import queue
import random
import threading
import time
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import openpyxl
def read_data(path):
# 打开 Excel 文件
wb = openpyxl.load_workbook(path)
sheet = wb.active
# 获取表头
# 创建一个空列表来存储数据
header = []
data = []
# 遍历每行数据并添加到列表中
row_count = 0
for row in sheet.iter_rows(values_only=True):
if row_count == 0:
header = list(row)
row_count = 1
else:
row_data = {header[i]: value for i, value in enumerate(row)}
data.append(row_data)
# 输出列表中的数据
return data
class RandomPickerApp:
def __init__(self, root):
self.root = root
self.root.title("随机抽取APP")
self.personnel_data = [] # 修改为列表,存储字典格式的个人数据
self.create_widgets()
def create_widgets(self):
# 人员管理框架
manage_frame = ttk.LabelFrame(self.root, text="人员管理")
manage_frame.grid(row=0, column=0, padx=10, pady=10)
ttk.Button(manage_frame, text="加载Excel", command=self.load_excel).grid(row=0, column=0, padx=5, pady=5)
# 随机抽取框架
picker_frame = ttk.LabelFrame(self.root, text="随机抽取")
picker_frame.grid(row=0, column=1, padx=10, pady=10)
ttk.Label(picker_frame, text="抽取名称:").grid(row=0, column=0, padx=5, pady=5)
self.draw_name_entry = ttk.Entry(picker_frame)
self.draw_name_entry.grid(row=0, column=1, padx=5, pady=5)
ttk.Label(picker_frame, text="抽取数量:").grid(row=1, column=0, padx=5, pady=5)
self.draw_count_entry = ttk.Entry(picker_frame)
self.draw_count_entry.grid(row=1, column=1, padx=5, pady=5)
ttk.Label(picker_frame, text="科室:").grid(row=3, column=0, padx=5, pady=5)
self.avoid_organization_entry = ttk.Entry(picker_frame)
self.avoid_organization_entry.grid(row=3, column=1, padx=5, pady=5)
ttk.Button(picker_frame, text="开始抽取", command=self.start_drawing).grid(row=4, column=0, columnspan=2, pady=10)
style = ttk.Style()
style.theme_use('xpnative') # 可以选择其他主题,如 aqua、vista、xpnative等
def load_excel(self):
try:
file_path = filedialog.askopenfilename(title="选择人员数据文件", filetypes=[("Excel 文件", "*.xlsx")])
if not file_path:
return
self.personnel_data = read_data(file_path)
messagebox.showinfo("成功", "人员数据加载成功!")
except Exception as e:
messagebox.showerror("错误", f"加载人员数据失败:{str(e)}")
def start_drawing(self):
draw_name = self.draw_name_entry.get()
draw_count_str = self.draw_count_entry.get()
if not draw_name:
messagebox.showerror("错误", "请输入有效的抽取名称。")
return
if not draw_count_str:
messagebox.showerror("错误", "请输入有效的抽取数量。")
return
try:
draw_count = int(draw_count_str)
except ValueError:
messagebox.showerror("错误", "请输入有效的抽取数量。")
return
avoid_organization = self.avoid_organization_entry.get()
self.available_people = self.get_available_people(avoid_organization)
self.show_extract_result(self.available_people, f"{draw_name} 抽取结果", draw_count)
def item_factory(self, person: dict):
res = [person['姓名'], person['性别'], person['电话']]
res = [r for r in res if r]
return ' '.join(res)
def show_extract_result(self, available_people: list, title: str, draw_count: int):
custom_box = tk.Toplevel(self.root)
ttk.Label(custom_box, text=title).grid(row=0, column=0, padx=5)
picker_frame = ttk.LabelFrame(custom_box)
picker_frame.grid(padx=10)
self.label_text_list = [tk.StringVar() for _ in range(draw_count)]
for i in range(draw_count):
ttk.Label(picker_frame, text=f"结果{i + 1}:").grid(row=i, column=0, padx=5, pady=5)
label_text = self.label_text_list[i]
draw_name_label = ttk.Label(picker_frame, textvariable=label_text, width=30)
draw_name_label.grid(row=i, column=1, padx=5, pady=5)
communcte_queue = queue.Queue(maxsize=1)
ttk.Button(picker_frame, text="停止",
command=functools.partial(self.stop_extract_loop, communcte_queue, label_text,
available_people)).grid(row=i, column=2, padx=5, pady=5)
threading.Thread(target=self.start_extract_loop, args=(communcte_queue, label_text, available_people),
daemon=True).start()
# 注意这里传递的是 available_people 而非其副本
def stop_extract_loop(self, communcte_queue: queue.Queue, textvariable: tk.StringVar, available_people: list):
if communcte_queue.empty():
communcte_queue.put(True)
# 从显示的文本中获取当前选中的人员姓名
current_selected = textvariable.get().split(",")[0] # 假设姓名是字符串的第一部分
# 在 available_people 列表中找到并移除这个人员
with threading.Lock(): # 确保线程安全
for person in available_people[:]:
if person["姓名"] == current_selected:
available_people.remove(person)
break
def start_extract_loop(self, communcte_queue: queue.Queue, textvariable: tk.StringVar, available_people: list):
selected_person = None
while True:
if not available_people: # 如果没有可用人员,跳出循环
textvariable.set("没有更多人员可抽取")
break
selected_person = random.choice(available_people)
textvariable.set(self.item_factory(selected_person))
time.sleep(0.01) # 设置更新间隔
if not communcte_queue.empty():
communcte_queue.get() # 清空队列
break # 停止循环
if selected_person and selected_person in available_people:
available_people.remove(selected_person)
def get_available_people(self, avoid_organization):
return [person for person in self.personnel_data if
(not avoid_organization or person["科室"] != avoid_organization)]
if __name__ == "__main__":
root = tk.Tk()
app = RandomPickerApp(root)
root.mainloop()