Python制作一个随机抽奖小工具的实现
作者:可以叫我才哥 发布时间:2022-10-22 03:53:29
最近在工作中面向社群玩家组织了一场活动,需要进行随机抽奖,参考之前小明大佬的案例,再结合自己的需求,做了一个简单的随机抽奖小工具。
今天我就来顺便介绍一下这个小工具的制作过程吧!
先看效果:
1. 核心功能设计
针对随机抽奖的小工具,需要可以导入参与抽奖的人员名单,然后选择不同的奖励类型进行随机抽取获奖名单并导出。
那么,简单进行需求拆解,大致梳理出以下核心功能:
名单导入
为了避免出现重名情况,这里我们约定以下几点:
①导入参与抽奖的人员名单文件(xlsx
类型文件)
②数据第一列为ID,第二列为name
参考格式案例
奖项类型选择
奖项类型是指一等奖、二等奖这类标识语,这里我们内置了特等奖-六等奖共7个选项供选取
本轮人数
本轮人数是指每次抽奖时一次性抽取的获奖人数,默认值为5
①当填入的数字超过剩余未获奖人数时,会进行提示并显示未获奖人数
②当填入的数字为0表示轮空,也需要手动结束
③当填入的数字为负数时,点击抽奖无响应
④当填入的非数字时,会进行提示需要输入正确数字
抽奖时轮播区域
用于显示抽奖中随机滚动参与本轮抽奖的人员名单
人员名单
当选择正确的人员名单文件后,这里会自动显示人员信息列表
中奖记录
记录每次抽取的奖项类型及获奖名单
开始抽奖
①开始抽奖时,会先判断抽奖设置是否满足条件,否则会有相关提示
②抽奖中点击开始抽奖会提示正在抽奖中
结束
①非抽奖状态下点击结束无响应
②抽奖中点击结束将显示本次抽奖结果
重置
①重置会清掉历史抽奖记录(含本地文件,如有必要建议对中奖名单留档)
②抽奖中点击重置会提示正在抽奖中
③非抽奖状态点击重置会提示该操作会删除历史记录,是否确认
基本功能点确认后,我们就开始进行GUI设计。
2. GUI设计与实现
基于功能点,我们用axure
简单进行UI布局设计
,然后再通过GUI
开发库进行设计,这里依旧采用的是pysimplegui
,主要是简单方便。
基于GUI设计,我们编码如下:
nameList_column = [
[sg.Text('人员名单:')],
[sg.Listbox(values=[], size=(20, 10), key='nameList')],
]
result_column = [
[sg.Text('中奖记录:')],
[sg.Multiline('', size=(48, 10), key='result', text_color='DeepPink')],
]
# 主题设置
sg.theme('SystemDefaultForReal')
# 布局设置
layout = [[sg.Text('选择参与抽奖人员名单文件:', font=('微软雅黑', 12)), sg.InputText('', key='_file', size=(50, 1), font=('微软雅黑', 10), enable_events=True), sg.FileBrowse('打开', file_types=(('Text Files', '*.xlsx'),), size=(10, 1), font=('微软雅黑', 11))],
[sg.Frame(layout=[
[sg.Text('本轮奖项:', font=('微软雅黑', 12)), sg.Combo(['特等奖', '一等奖', '二等奖', '三等奖', '四等奖', '五等奖', '六等奖'], font=('微软雅黑', 10), default_value='特等奖', size=(15, 5), key='_type'),
sg.Text('本轮人数:', font=('微软雅黑', 12)), sg.InputText('5', key='_num', size=(38, 1), font=('微软雅黑', 10))],
],
title='抽奖设置', title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='请进行抽奖设置后再开始抽奖')],
[sg.Multiline(size=(48, 5), font=(
'微软雅黑', 18), text_color='Blue', key='luckyName', justification='center')],
[sg.Column(nameList_column), sg.Column(result_column)],
[sg.Text('操作说明:', font=('微软雅黑', 12))],
[sg.Text('①先选择参与抽奖的人员名单xlsx文件,人员名单文件包含ID和name两个字段\n②获奖名单将存在小工具所在文件夹,重置会删除历史记录文件', font=('微软雅黑', 10)),
sg.Text('', font=('微软雅黑', 12), size=(5, 1)),
sg.Button('开始抽奖', font=('微软雅黑', 12), button_color='Orange'),
sg.Button('结束', font=('微软雅黑', 12), button_color='red'),
sg.Button('重置', font=('微软雅黑', 12), button_color='red'), ],
]
# 创建窗口
window = sg.Window('抽奖小工具,作者@微信公众号:可以叫我才哥', layout,
font=('微软雅黑', 12), default_element_size=(50, 1))
其包含的控件如下:
Text 文本
InputText 输入文本框
FileBrowse 文件浏览
Multiline 多行文本框
Combo 下拉框
Listbox 列表
Button 按钮
需要注意的是这里有个Frame组件,用于layout嵌套,可以很好地模块化UI布局。
3. 功能实现
在本案例中,需要实现三个功能,分别是:读取人员名单、随机抽奖以及保存中奖名单。
3.1 读取人员名单
这里采用的是openpyxl
读取表格数据并获得某几列的值,由于存在表头,所以最后不需要表头
def nameList(window):
fileName = values['_file']
try:
wb = openpyxl.load_workbook(fileName)
active_sheet = wb.active
names = [cell_object.value for cell_object in list(active_sheet.columns)[1]][1:]
ids = [cell_object.value for cell_object in list(active_sheet.columns)[0]][1:]
names = [name+'_'+str(id_) for name, id_ in zip(names, ids)]
window['nameList'].update(names)
return names
except:
sg.popup('请选择正确格式的的人员名单文件', title='提示',)
3.2. 随机抽奖
由于我们需要一次随机抽取的人数存在多个,所以这里用的是random.sample()
,需要注意的是传入的参数中names是需要去掉已中奖名单
def Result(window, names):
global is_run, luckyNames
_type = values['_type'] # 本轮奖项类型
_num = int(values['_num']) # 本轮人数
while True:
randomName = random.sample(names, k=_num)
luckyName = ' '.join(randomName)
window['luckyName'].update(luckyName)
if not is_run:
headers = ['奖项', '名单']
toCsv(headers, [_type]*len(randomName), randomName, lucky)
luckyNames = luckyNames + _type+' : '+luckyName+'\n\n'
window['result'].update(luckyNames)
return
time.sleep(0.088)
3.3. 保存中奖名单
这里我们用的是csv
库的方法,追加存储
def toCsv(headers, col1, col2, file):
# 存在则追加,不存在则新建
if os.path.exists(lucky):
with open(lucky, 'a', encoding='utf_8_sig', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(zip(col1, col2))
else:
with open(lucky, 'w', encoding='utf_8_sig', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(headers)
writer.writerows(zip(col1, col2))
完成核心功能函数后,我们再进行GUI交互逻辑的实现。
3.4. GUI交互逻辑
这里有两个全局变量,其中一个用于记录当前抽奖状态,另外一个用于存储当前已经获奖的人员信息。关于交互逻辑的详情,大家可以结合核心功能需求及以下代码了解。
# 初始状态
is_run = False
luckyNames = ''
# 事件循环
while True:
event, values = window.read()
if event in (None, '关闭程序'):
break
if event == '_file':
nameList(window)
if event == '开始抽奖':
if is_run:
sg.popup('抽奖进行中,无需重复操作......', title='提示')
continue
try:
names = nameList(window) # 人员名单
_num = int(values['_num']) # 本轮人数
lucky = '中奖名单.csv' # 中奖名单
if os.path.exists(lucky):
with open('中奖名单.csv', 'r', encoding='utf_8_sig') as f:
reader = csv.reader(f)
selectedNames = set([i[1] for i in reader][1:])
names_set = set(names)-selectedNames
else:
names_set = set(names)
if len(names_set) >= _num:
is_run = True
_thread.start_new_thread(Result, (window, names_set))
else:
sg.popup(
f'请选择正确本轮抽奖人数(当前 {len(names_set)} 个未中奖人数)', title='提示')
except:
sg.popup('请选择正确本轮抽奖人数(别超过总人数哦)', title='提示')
elif event == '结束':
is_run = False
elif event == '重置':
if is_run:
sg.popup('抽奖进行中,请等待抽奖结束后重置...', title='提示')
continue
yes_no = sg.popup_yes_no(
'重置会清楚历史数据,是否执行此操作??', text_color='red', title='提示')
if yes_no == 'Yes':
try:
os.remove(lucky)
luckyNames = ''
window['result'].update(luckyNames)
window['luckyName'].update(luckyNames)
sg.popup('抽奖历史记录已被重置......', title='提示')
except:
sg.popup('无抽奖历史记录......', title='提示')
window.close()
基于此,我们就完成了随机抽奖小工具的制作。
启动页如下:
最后,大家感兴趣就可以将代码打包成exe可执行文件了,我这边打包下来大概10MB左右大小。
来源:https://blog.csdn.net/dxawdc/article/details/118465887
猜你喜欢
- 1.类方法类方法是从属于"类对象"的方法。类对象可以通过装饰器@classmethod来定义,具体格式如下:@class
- 我们最常用的 DBD::mysql 模块,我发现是难住很多人的地方.因为安装老是失败,下面我介绍一下解决方法,比如我使用 cpanm 安装,
- view.pyfrom django.views.generic import ListView,DetailViewfrom xxxx.m
- 常用配置以下配置能使用File -> New Projects Settings -> Settings for New Pro
- 1. 解决思路首先要获得这张验证码的图片,但是该图片一般都是用的js写的,不能够通过url进行下载。解决方案:截图然后根据该图片的定位和长高
- 这个是我在蓝色看到的,楼主想实现图片按比例缩放的功能(缩略图),把图片固定在一定的宽高范围内,不会变形,失真。例如:缩略图的框是94px*9
- HTML5 是近十年来 Web 标准最巨大的飞跃。和以前的版本不同,HTML 5 并非仅仅用来表示 Web 内容,它的使命是将 W
- 前言日志无论对于程序还是程序员都非常重要,有多重要呢,想要长期在公司健健康康的干下去就得学会阶段性划水,阶段性划水的一大关键的就是干活快过预
- python字符串连接的方法,一般有以下三种:方法1:直接通过加号(+)操作符连接website = 'python' +
- 最近学习Python接口测试,对于接口测试完全小白。大概一周的学习成果进行总结。1.接口测试:目前涉及到的只是对简单单一的接口进行参数传递,
- 本文实例为大家分享了tensorflow实现弹性网络回归算法,供大家参考,具体内容如下python代码:#用tensorflow实现弹性网络
- 通过logging模块,重写一个logging2模块,独立开启线程,将待写的日志信息异步放入队列,做到日志输出不影响主流程性能,环境pyth
- 视频地址我用20行代码,帮女神破解相册密码一、事情是这样的今早上班,公司女神小姐姐说,她去年去三亚旅游的照片打不开了好奇问了一下才知道。原来
- %有哪几种含义?查找手册翻看《The Python Libary Reference》python库指南中附录index部分(P1899):
- 最近公司的数据库随着业务量的增多,日志文件巨大(超过300G),造成磁盘空间不够用,进而后来的访问数据库请求无法访问。网上类似的方法也很多,
- MySQL的自增id都定义了初始值,然后不断加步长。虽然自然数没有上限,但定义了表示这个数的字节长度,计算机存储就有上限。比如,无符号整型(
- 前言前面我们已经介绍了 python面向对象入门教程之从代码复用开始(一) ,这篇文章主要介绍的是关于Python面向对象之设置对
- 八卦为先八卦是种优良品质,特别是用在技术上时。来看几个Reset CSS的八卦问题吧:你知道世界上第一份reset.css在哪么?* { m
- 使用循环神经网络(RNN)实现影评情感分类作为对循环神经网络的实践,我用循环神经网络做了个影评情感的分类,即判断影评的感 * 彩是正面的,还是
- 目录1.mvc vs mvtmvc:mvt:2.虚拟环境3.安装包4.创建django项目5.创建应用6.模型ORM选项 说明7.后台管理系