下周我们公司的圣诞 Party 活动安排有抽奖环节,由于不方便采用手机抽奖,且目前选用的电脑端在线抽奖会出现卡顿情况,最近我就尝试着用 Python 实现抽奖功能。目前进展不错,也想分享给大家,由于涉及隐私嘛,做了番保密修改。

先来看看效果视频吧(背景音乐很好听哦:)

人家需不需要呢咱也不敢问,反正抽奖程序是做好了,请大家过目:

运行前准备好参与抽奖的好汉名单,本程序会自动读取表格文件,将待抽奖的各位好汉展示在左侧奖池中,只要点击图中小鹿的红鼻子,会默认抽取三等奖(共十位)。

可以看到,抽奖时好汉名字会在中央滚动展示,当再次点击红鼻子完成单次抽奖时,中奖的名字会从左侧奖池转移到右侧获奖榜上。

一、二等奖分别五位,与三等奖抽取的区别在于要先选择右侧 1 号金色或 2 号银色标志,根据点选标志抽取相应奖项。

当然,如果三等奖未完成,也可以点选 1 号金标 或 2 号银标 先行抽取,之后再通过点 3 号铜标 完成三等奖的抽取。在获奖榜满额时,再次抽奖会触发弹框提醒。

此外,左下方的 "Let's go!" 字样是重置开关,点击会重新载入数据进行抽奖。

当然,除了鼠标点击事件的控制,该抽奖程序也添加了键盘控制:例如数字键可以直接选择奖项,空格键等同于红鼻子控制,Esc 键退出抽奖等。

如上便是目前抽奖程序的功能和界面了,下面分享下我在设计与编码过程中的路线和想法。


需求与设计

首先归纳下整个抽奖程序的需求:

  1. 基本功能是实现名单中的随机抽取

  2. 活动穿插三轮抽奖,不能重复中奖

  3. 尽量美观

  4. 打消暗箱操作的怀疑

基于总结的需求点,我整理的设计方案如下:

  1. 名单自动载入至列表中

  2. 随机抽取名单列表,抽中后移除该元素

  3. 图形界面展现抽奖过程和结果,选用 tkinter 来实现

  4. 绑定鼠标、键盘控制抽奖过程

滚动随机数

首先搜索 “Python 抽奖程序”,在众多素材中看到了一份可以 tkinter 界面动态展示随机数的代码。拷贝过来运行,效果如图:

点击图中按钮时,屏幕中滚动出现 1000 以内的随机数,代码逻辑如下:

# while 循环控制界面
while True:# 延时操作time.sleep(0.1)# 产生随机数r = random.choice(range(1000))# 将随机数赋给页面的组件上self.btn1['text'] = r

在 while 循环中设置 0.1 秒延迟,通过 random.choice() 在 range(1000) 生成随机数,将其绑定在 tkinter 界面上展现。这样随着 while 循环的进行,每个随机数在界面上停留 0.1 秒,就产生了滚动随机数的效果。

由于该代码中将整个抽奖过程定义为了一个对象,果断选取此份代码当作核心代码来予以拓展,也借此机会加深下相关理解。

我们要做的就是先消化吸收此代码,然后站在其肩膀上定制并完善自己需要的功能。

# 代码来自于https://blog.csdn.net/weixin_39833509/article/details/88700565
import tkinter
import time
import threading
import random
class Choujiang:
#初始化魔术方法def __init__(self):#准备好界面self.root = tkinter.Tk()self.root.title('lowB版转盘')self.root.minsize(600, 600)# 声明一个是否按下开始的变量self.isloop = Falseself.newloop = False#调用设置界面的方法self.setwindow()self.root.mainloop()#界面布局方法def setwindow(self):#开始停止按钮self.btn_start = tkinter.Button(self.root, text = '开始/停止', command = self.newtask,bg='gold')self.btn_start.place(x=250, y=250, width=100, height=50)self.btn1 = tkinter.Button(self.root, text='', bg='red')self.btn1.config(font=("Courier", 50))self.btn1.place(x=200, y=130, width=200, height=50)self.girlfrends = list(range(1000))def rounds(self):# 判断是否开始循环if self.isloop == True:return# 初始化计数 变量i = 0# 死循环while True:if self.newloop == True:self.newloop = Falsereturn# 延时操作time.sleep(0.1)# 将所有的组件背景变为白色r = random.choice(range(1000))self.btn1['text'] = r# 建立一个新线程的函数def newtask(self):if self.isloop == False:# 建立线程t = threading.Thread(target = self.rounds)# 开启线程运行t.start()# 设置循环开始标志ask(self):nknewtasself.isloop = Trueelif self.isloop == True:self.isloop = Falseself.newloop = True
c = Choujiang()

滚动名单

因为公司有提供员工名做抽奖用,类比着来,也准备了一份梁山好汉的名单表格。基于刚刚动态展示随机数的代码,我们要做的是载入表格,将名单数据转化为列表。

# 读取表格中的名单数据,存入列表中
data = pd.read_excel("demo.xlsx")
name_list=[item for item in data['名字']]

把刚代码中的提取随机数代码替换成 random.choice(名单列表) 就可以了。

# 仍是 while 循环控制界面
while True:# 延时操作time.sleep(0.1)# 将随机数抽取范围替换成名字列表r = random.choice(name_list)# 将随机名字赋值给页面组件self.btn1['text'] = r

效果如下:

界面初始布局

在动态随机名字的界面基础上,添加背景图展现:

# 准备好界面
self.root = tkinter.Tk()
self.root.title("水泊梁山 2019 圣诞大抽奖")
self.root.geometry('1360x700+0+0')  # 定义界面大小
self.root.resizable(False, False)# 添加背景图片
self.canvas = tkinter.Canvas(self.root,width=1360,  # 指定Canvas组件的宽度height=700,  # 指定Canvas组件的高度bg='white')  # 指定Canvas组件的背景色
self.image = Image.open("static/background.png")
self.im = ImageTk.PhotoImage(self.image)
self.canvas.create_image(680, 350, image=self.im)  # 使用create_image将图片添加到Canvas组件中
self.canvas.pack()

基于奖项划分,添加相应的按钮控制和中奖名单展现:

# 以一等奖为例,此处代码只是示例,参数不准确
# 添加一等奖的按钮组件 Button
self.first = tkinter.Button(self.root, text = '一等奖', command = self.set_first,bg='gold')
# 将该按钮置于界面相应位置
self.first.place(x=1070, y=180, width=80, height=50)
# 设置获奖榜展示字体
myFont = font.Font(size=20)
# 添加一等奖的获奖名单展示组件 Listbox
self.target_1 = tkinter.Listbox(self.root,height=5,font=myFont,bg="lemonchiffon",bd=0,fg="olive")
# 将展示组件添加到界面中
self.target_1.place(x=1080, y=240, width=70, height=130)

添加总名单的展示区域以及重设按钮:

# 总名单展示区域选用 Text 组件
self.source = tkinter.Text(self.root,bg="navajowhite",fg="dimgray")
# 将该组件添加到界面中
self.source.place(x=100, y=250, width=300, height=290)
# 向组件中插入数据
self.source.insert(tkinter.END,("、").join(self.data))
# 重启按钮 Button
self.btn_reset = tkinter.Button(self.root, text = '重启', command = self.reset ,bg='gold')
# 重启按钮添加到界面中
self.btn_reset.place(x=180, y=550, width=100, height=50)

经过上述代码的布局,最初界面效果如下图:

进一步绑定并对应好数据,便可实现基本功能。

界面优化

首先是布局,两个思路:其一是在背景图上做文章,相应位置添加装饰元素;其二是 tkinter 组件上下功夫,优化组件展示样式或者替换成更美观的样式。

说实话,写功能代码的时间和此部分界面优化的时间比起来真的小巫见大巫了。首先并不清楚能不能实现某种样式,其次 tkinter 自己也不熟,好多对组件都是自己在 Photoshop 中定位并加工处理的。

背景图优化

背景图方面,添加了图中的小鹿,原图是这样的:

通过 PS 将其抠图放到背景图中当作“摇奖展示台”。同时背景图添加公司名称、活动作为标题,并在左侧为总名单展示区域添加边框。最终效果如下:

组件优化

最初的想法是,按钮不好看,尝试隐藏按钮保留功能,尝试无果。最终方案是,将 Button 组件换成 Label 组件,在 Label 中展示相应位置的背景图,通过 bind 绑定鼠标点击事件。换句话说,我将红鼻子区域的图片当成一个 Label 置于界面中并绑定抽奖动作,那么一点击红鼻子就会开启/停止抽奖。

所有用来替换 Button 组件的 Label 图片如上:

  • nose.png 即红鼻子局部图,对应 “开始/停止”;

  • 001.png 即 1 号金标图,对应 “一等奖”;

  • 002.png 即 2 号银标图,对应 “二等奖”;

  • 003.png 即 3 号铜标图,对应 “三等奖”;

  • reset.png  为 "Let's go!" 局部图,对应 “重启”

对于展现获奖名单的 Listbox 组件,利用其每项占一行的特点,通过调整其组件大小和颜色,稍作优化,未做大改。对于被展现名字的处理,我采用的策略是检测到两个字的名字就给其中间加个中文空格,这样所有名字都会转化为三个中文字符,方便统一样式处理。

# temp 获取到被抽中的名字
temp = random.choice(self.data)
# 判断名字是否为2字
if len(temp) == 2:# 二字名字中间添加个中文字符r = temp[0]+f"{chr(12288)}"+temp[1]
else:# 三字名字保持不变(数据中无四字名字出现)r = temp

至于展现总名单的 Text 组件,简单调整大小、修改背景和字体颜色。

最终再将各组件安排到设计好的位置中,就产生了开头时抽奖程序的界面:

功能添加

因为是 Party 需要,如果鼠标点击不方便的话,还可以对程序添加键盘控制:

# 添加键盘控制
self.root.bind("1", self.set_first)
self.root.bind("2", self.set_second)
self.root.bind("3", self.set_third)
# 空格键 开始/停止
self.root.bind("<space>", self.newtask)
# Esc 键退出程序界面
self.root.bind("<Escape>", self.close)

总结

思路与流程大致如上,现在做完了再回顾,确实,优化细节比实现功能要繁琐的多。尤其是用到 tkinter 图形界面中的诸多组件,要配合着通过 PS 来修改图片样式等。说实话,python 有没长进不知道,PS 技术蹭蹭蹭地涨。

想要从零实现本篇中的程序,可能对 tkinter 的使用、多线程的应用以及对象的了解都要求比较高。但像我这次的选择,基于半成品的 tkinter 抽取随机数代码的基础上去尝试,更多涉及的就是功能完善和界面上优化了,就完成任务而言还是可以加速很多的。

总体来看本次任务完成度,个人感觉还不错,该有的都有、也添加了些小细节展示。后续可以添加导出中奖名单、抽奖过程存档等功能,但我们这边目前还用不到就先不添加了。

整个编码过程也是尽力在找更好的展现或实现方法,可能有些组件或方法自己没接触过没有概念,也欢迎大家予以指点!

代码下载

源码链接:https://github.com/pengfexue2/lucky_draw.git。其中附上了背景图的 PS 文件,如有需要可以直接修改该文件生成定制版图片。

推荐阅读:

李子柒一年能赚多少钱,数据量化给你看
GitHub 上有个沙雕开发者,做了款斗图工具后火了...
P站2019年终报告.PDF
Heartrate:一个牛逼的工具,Python执行实时可视化


关注“Python之禅“,学地道的Python技术

好文和朋友一起看~

Python制作一个圣诞抽奖程序,原来如此简单相关推荐

  1. 用Python制作一个成绩分析程序

    用Python做一个成绩分析程序 第一步:导库 第二步:导入数据 第三步:输出数据并建立分隔栏 第四步:完成分数统计并画出饼图 本程序可以实现画班级成绩饼图的效果. 第一步:导库 from pyech ...

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

    最近在工作中面向社群玩家组织了一场活动,需要进行随机抽奖,参考之前小明大佬的案例,再结合自己的需求,做了一个简单的随机抽奖小工具. 今天我就来顺便介绍一下这个小工具的制作过程吧! 先看效果: 1. 核 ...

  3. Python制作一个简单的抽奖软件(二)

    Python制作一个简单的抽奖软件(二) 认识QT 因为都对 QT和tkinter都没用过,之前简单使用tkinter后发现,界面调整不太好弄.然后度娘了之后,QT是强大GUI库之一,很多人都推荐它. ...

  4. 怎么用python制作简单的程序-神级程序员教你如何用python制作一个牛逼的外挂!...

    玩过电脑游戏的同学对于外挂肯定不陌生,但是你在用外挂的时候有没有想过如何做一个外挂呢?(当然用外挂不是那么道义哈,呵呵),那我们就来看一下如何用python来制作一个外挂.... 我打开了4399小游 ...

  5. python制作解压工具_使用python制作一个解压缩软件

    python实现解压缩的重要模块就是--zipfile,其次是os 安装zipfile模块 首先得安装zipfile模块,打开cmd输入一下命令即可安装 pip install zipfile os是 ...

  6. python编写一个软件-使用python制作一个解压缩软件

    python实现解压缩的重要模块就是――zipfile,其次是os 安装zipfile模块 首先得安装zipfile模块,打开cmd输入一下命令即可安装 pip install zipfile os是 ...

  7. 手把手教你如何用Python制作一个电子相册?末附python教程

    这里简单介绍一下python制作电子相册的过程,主要用到tkinter和pillow这2个库,tkinter用于窗口显示照片,pillow用来处理照片,照片切换分为2种方式,一种是自动切换(每隔5秒) ...

  8. python如何制作一个工程软件_使用python制作一个解压缩软件

    python实现解压缩的重要模块就是--zipfile,其次是os 安装zipfile模块 首先得安装zipfile模块,打开cmd输入一下命令即可安装 pip install zipfile os是 ...

  9. python如何制作一个工程软件_如何利用python制作一个解压缩软件-Go语言中文社区...

    如何利用python制作一个解压缩软件 python实现解压缩的重要模块就是--zipfile,其次是os 安装zipfile模块 首先得安装zipfile模块,打开cmd输入一下命令即可安装 pip ...

  10. python可视化迷宫求解_如何用 Python 制作一个迷宫游戏

    相信大家都玩过迷宫的游戏,对于简单的迷宫,我们可以一眼就看出通路,但是对于复杂的迷宫,可能要仔细寻找好久,甚至耗费数天,然后可能还要分别从入口和出口两头寻找才能找的到通路,甚至也可能找不到通路. 虽然 ...

最新文章

  1. oracle数据库常用的99条查询语句
  2. excel字符串和单元格拼接_Excel实例分享-学会输入数据小技巧,让你的工作效率远超同事...
  3. 51. ExtJs4之Ext.util.JSON编码和解码JSON对象
  4. 2021常用单细胞数据库整理汇总
  5. seq_file机制
  6. hdu4965-Fast Matrix Calculation【矩阵乘法】
  7. CUDA: OpenCV requires enabled ‘cudev‘ module from ‘opencv_contrib
  8. 20 MM配置-BP业务伙伴-定义业务伙伴和供应商编码保持一致
  9. es6 Babel 转码器对修饰器的支持
  10. MySQL 8.0 安装部署3个注意事项
  11. 世界上最有能量的语言,一定要经常说!
  12. 【React Native开发】React Native控件之RefreshControl组件具体解释(21)
  13. JavaScript return的作用
  14. lol峡谷之巅区服务器位置,LOL: 论峡谷之巅和艾欧尼亚哪个区水平更高?
  15. GNS3中下载路由器
  16. DirectX修复工具全部文件修复失败或下载失败的解决方法
  17. 使用SCCM管理Office ProPlus(二)--升级最到最新更新
  18. python俄罗斯方块思路_python实现俄罗斯方块小游戏
  19. 特朗普对五角大楼云计算合同表示担忧
  20. stm32单片机里面的GPIO是什么意思?

热门文章

  1. 笔记本win7做wifi热点
  2. 模拟用户操作购物车添加商品修改数量
  3. 手机便签记事本下载,好用的手机便签记事本软件
  4. uniapp , 微信小程序 图片加载时闪烁
  5. java缺失_Java中找出缺失的数字
  6. bzoj1208 [HNOI2004]宠物收养所
  7. cocos2dx.3.17中用VS2017启动本地windows调试器出现脚本错误解决办法
  8. 微信小程序清除Webview缓存
  9. mysql ndb_搭建mysql NDB集群
  10. 关于linux的最新问题合集