随机抽取程序

前言

        随机抽取软件可以在各种应用场景中发挥作用。

        随机抽取器常见的应用场景有以下:

  1. 抽奖活动:在各种抽奖活动中,例如公司年会、促销活动或社交媒体抽奖,随机抽取软件可以帮助你从参与者中随机选取获奖者。
  2. 研究实验:在科学研究中,研究者可能需要随机选择样本或实验条件,以确保实验结果的可靠性和代表性。
  3. 民意调查:在进行民意调查时,你可能需要从大量受访者中随机选择一部分人来参与调查,以获得更具代表性的结果。
  4. 随机分组:在实验设计、医学研究或教育研究中,研究者可能需要将被试对象随机分配到不同的处理组或对照组,以便比较不同组之间的差异。
  5. 游戏和竞赛:在游戏、竞赛或体育比赛中,随机抽取软件可以用于分配参与者的顺序、对手或队伍,以保证公平性。
  6. 教学活动:在课堂上,教师可以使用随机抽取软件来选择回答问题的学生,以增加参与度和公平性。

工具界面

代码

#!/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()

数据文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marst·Zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值