社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用Python制作一个随机抽奖小工具

Crossin的编程教室 • 1 月前 • 180 次点击  

最近在工作中面向社群玩家组织了一场活动,需要进行随机抽奖,参考之前小明大佬的案例,再结合自己的需求,做了一个简单的随机抽奖小工具。

今天我就来顺便介绍一下这个小工具的制作过程吧!

先看效果:

1. 核心功能设计

针对随机抽奖的小工具,需要可以导入参与抽奖的人员名单,然后选择不同的奖励类型进行随机抽取获奖名单并导出。

那么,简单进行需求拆解,大致梳理出以下核心功能:

  • 名单导入

为了避免出现重名情况,这里我们约定以下几点:

①导入参与抽奖的人员名单文件(xlsx类型文件)
②数据第一列为ID,第二列为name

参考格式案例

案例
  • 奖项类型选择

奖项类型是指一等奖、二等奖这类标识语,这里我们内置了特等奖-六等奖共7个选项供选取

  • 本轮人数

本轮人数是指每次抽奖时一次性抽取的获奖人数,默认值为5

①当填入的数字超过剩余未获奖人数时,会进行提示并显示未获奖人数

②当填入的数字为0表示轮空,也需要手动结束

③当填入的数字为负数时,点击抽奖无响应

④当填入的非数字时,会进行提示需要输入正确数字

  • 抽奖时轮播区域

用于显示抽奖中随机滚动参与本轮抽奖的人员名单

  • 人员名单

当选择正确的人员名单文件后,这里会自动显示人员信息列表

  • 中奖记录

记录每次抽取的奖项类型及获奖名单

  • 开始抽奖

①开始抽奖时,会先判断抽奖设置是否满足条件,否则会有相关提示

②抽奖中点击开始抽奖会提示正在抽奖中

  • 结束

①非抽奖状态下点击结束无响应

②抽奖中点击结束将显示本次抽奖结果

  • 重置

①重置会清掉历史抽奖记录(含本地文件,如有必要建议对中奖名单留档)

②抽奖中点击重置会提示正在抽奖中

③非抽奖状态点击重置会提示该操作会删除历史记录,是否确认

基本功能点确认后,我们就开始进行GUI设计。

2. GUI设计与实现

基于功能点,我们用axure简单进行UI布局设计,然后再通过GUI开发库进行设计,这里依旧采用的是pysimplegui,主要是简单方便。

UI布局设计-axure

基于GUI设计,我们编码如下:

nameList_column = [
    [sg.Text('人员名单:')],
    [sg.Listbox(values=[], size=(2010), key='nameList')],
]
result_column = [
    [sg.Text('中奖记录:')],
    [sg.Multiline('', size=(4810), key='result', text_color='DeepPink')],
]

# 主题设置
sg.theme('SystemDefaultForReal')

# 布局设置
layout = [[sg.Text('选择参与抽奖人员名单文件:', font=('微软雅黑'12)), sg.InputText('', key='_file', size=(501), font=('微软雅黑'10), enable_events=True), sg.FileBrowse('打开', file_types=(('Text Files''*.xlsx'),), size=(101), font=('微软雅黑'11))],
          [sg.Frame(layout=[
              [sg.Text('本轮奖项:', font=('微软雅黑'12)), sg.Combo(['特等奖''一等奖''二等奖''三等奖''四等奖''五等奖''六等奖'], font=('微软雅黑'10), default_value='特等奖', size=(155), key='_type'),
               sg.Text('本轮人数:', font=('微软雅黑'12)), sg.InputText('5', key='_num', size=(381), font=('微软雅黑'10))],
          ],
              title='抽奖设置', title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='请进行抽奖设置后再开始抽奖')],
          [sg.Multiline(size=(485), 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=(51)),
           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=(501))

其包含的控件如下:

  • 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[1for 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左右大小。

关于打包操作,大家可以参考《如何将Python版「羊了个羊」打包成exe文件》了解哈。



Crossin的新书《码上行动:用ChatGPT学会Python编程》已经上市了。本书以ChatGPT为辅助,系统全面地讲解了如何掌握Python编程,适合Python零基础入门的读者学习。【点此查看详细介绍】
购买后可加入读者交流群,Crossin为你开启陪读模式,解答你在阅读本书时的一切疑问。
Crossin的其他书籍:


添加微信 crossin123 ,加入编程教室共同学习~

感谢转发点赞的各位~
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/175546
 
180 次点击