水泊梁山迎毛线的圣诞?

还 Python 抽奖助好汉?你来抽个我看看!

——息怒息怒,是这样:

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

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

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

文章结尾附有完整版细节视频。可以看到,抽奖时好汉名字会在中央滚动展示,当再次点击红鼻子完成单次抽奖时,中奖的名字会从左侧奖池转移到右侧获奖榜上。

一、二等奖分别五位,与三等奖抽取的区别在于要先选择右侧 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 秒,就产生了滚动随机数的效果。

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

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

import tkinterimport timeimport threadingimport randomclass Choujiang:#初始化魔术方法    def __init__(self):        #准备好界面        self.root = tkinter.Tk()        self.root.title('lowB版转盘')        self.root.minsize(600, 600)        # 声明一个是否按下开始的变量        self.isloop = False        self.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 = False                return            # 延时操作            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):nknewtas            self.isloop = True        elif self.isloop == True:            self.isloop = False            self.newloop = Truec = 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()

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

# 以一等奖为例,此处代码只是示例,参数不准确# 添加一等奖的按钮组件 Buttonself.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)# 添加一等奖的获奖名单展示组件 Listboxself.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))# 重启按钮 Buttonself.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 抽取随机数代码的基础上去尝试,更多涉及的就是功能完善和界面上优化了,就完成任务而言还是可以加速很多的。

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

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

水泊梁山迎佳节,Python 抽奖助好汉相关推荐

  1. python抽奖游戏_python实现转盘效果 python实现轮盘抽奖游戏

    本文实例为大家分享了python实现转盘效果的具体代码,供大家参考,具体内容如下 #抽奖 面向对象版本 import tkinter import time import threading clas ...

  2. python抽奖概率设计_辞职转行不如学Python,那些下载安装的坑,你真的都避开了嘛?...

    现在的职场竞争越来越激烈,不学上一两门新技能,保持自己知识更新,很容易被年轻后辈超越.有些人选择学一门外语,有些人选择学习职场上为人处事的能力. 有人选择Python. 因为,就业市场需要Python ...

  3. python抽奖概率设计_通过python分析原神,结果出现了“这种情况”

    最近迷上了原神这款游戏,趁着保研完,肝了两个星期,也氪了一些金.先不谈这款游戏可玩性有多高,但论氪金强度算是我从小到大玩的游戏中,能排得上第一的了. 对于这种寸卡寸金的游戏,如何在无穷无尽的抽卡活动中 ...

  4. python抽奖滚动界面_Python使用Tkinter实现转盘抽奖器的步骤详解

    我使用 Python 中的 Tkinter 模块实现了一个简单的滚动抽奖器,接下来继续写一个简单的转盘抽奖器. 滚动抽奖器与点名的场景相似,是从一群人中抽出中奖的人,奖品是提前确定了的,抽奖只是确定中 ...

  5. python 抽奖器_兄弟连学python (02) ----简易抽奖器

    import tkinter import random import tkinter.messagebox class choujiang: def __init__(self): self.roo ...

  6. python抽奖简单小程序游戏_python——(分别用两种方式实现)公司年会抽奖小程序...

    张三科技有限公司有300名员工,开年会抽奖,奖项如下 一等奖3名 : 泰国五日游 二等奖6名 :iphone手机 三等奖30名 :避孕套一盒 规则: 1.一共抽3次,第一次抽3等奖,第二次抽2等奖,第 ...

  7. python 抽奖库_用 python 写一个年会抽奖小程序

    使用 pyinstaller 打包工具常用参数指南 pyinstaller -F demo.py 参数 含义 -F 指定打包后只生成一个exe格式的文件 -D –onedir 创建一个目录,包含exe ...

  8. python 抽奖器_python编写实现抽奖器

    本文实例为大家分享了python编写实现抽奖器的具体代码,供大家参考,具体内容如下 # coding=utf-8 import sys import os import openpyxl if sys ...

  9. python 抽奖器_如何基于python实现年会抽奖工具

    用python来实现一个抽奖程序,供大家参考,具体内容如下 主要功能有 1.从一个csv文件中读入所有员工工号 2.将这些工号初始到一个列表中 3.用random模块下的choice函数来随机选择列表 ...

最新文章

  1. Redis命令参考简体中文版 2.4.1
  2. Vue.js 2.x render 渲染函数 JSX
  3. 【bzoj4408】[Fjoi 2016]神秘数 主席树
  4. 30+个必知的《人工智能》会议清单
  5. Java作业09-异常
  6. OpenCL memory object 之 Global memory (2)
  7. java write阻塞_java socket/output stream writes:他们阻塞?
  8. [Python学习25] 关于函数更多的练习
  9. Cause: org.apache.ibatis.binding.BindingException: Parameter 'eName' not found.解决方案
  10. BAT工程师自研存储引擎,火爆Github!!大家速度顶起来
  11. Ubuntu 安装 OpenCV 教程 【slam14讲行不通可以看看】
  12. android 通过platform.pk8,platform.x509.pem生成jks签名文件
  13. 地理空间数据云 Landsat 8 OLI_TIRS 影像数据下载详解
  14. python3 sorted自定义排序的函数
  15. 2010最有趣牛人语录100句
  16. 破解数字化转型难题,华为云一站式大数据BI赋能企业发展
  17. php 上传绕过,文件上传验证绕过技术总结
  18. 关于消防系统安装的一些规范
  19. 改变文字颜色html,html怎么改变字体大小和颜色
  20. ACM模板 | 学习笔记 树相关

热门文章

  1. linux指令:echo, head, tail
  2. 雷林鹏分享:PHP MySQL 创建数据库
  3. spring bean
  4. 老男孩教育每日一题-2017-04-25:怎样产生一个子shell?
  5. C语言简单的日期校验函数
  6. Web前端开发面试考点指南
  7. 解决Ssh/Scp报错:Someone Could Be Eavesdropping On You Right Now (Man-In-The-Middle Attack)!
  8. Spring 注解教程
  9. 消息队列面试 - 如何保证消息的可靠性传输?
  10. CentOS7升级内核kernel5.0