Python中基于Tkinter设计抽奖程序(第18节)


在如今这个高速发展的时代,年底的抽奖是每个公司不可或缺的环节。每到年底,抽奖这个话题很多人都会讨论,都希望自己可以中奖。很多公司每年为了实现公平抽奖,往往需要投入大量时间和精力。在AI技术日益成熟的今天,我们完全可以使用Python的Tkinter库实现一个简单的年会抽奖程序。Tkinter库是Python的GUI(图形用户界面)标准库,它的功能强大,允许我们创建复杂的窗口、按钮、输入框等控件。本节教程将介绍如何使用Tkinter库设计一个有趣且实用的年会抽奖程序。

1、抽奖程序介绍

假设某公司有2000名员工,年会抽奖的奖项设定如下:

特等奖1名:一台笔记本电脑

一等奖2名:一台液晶电视机

二等奖5名:一部手机

三等奖10名:一个电动剃须刀

四等奖50名:一个保温杯

鼓励奖100名:一包抽纸

抽奖规则:

  • 共抽6次,第一次抽特等奖,第二次抽一等奖,第三次抽二等奖,以此类推。

  • 每个员工只有一次中奖机会,不得重复中奖。

首先,打开抽奖程序,在输入框中输入所有的抽奖名单,注意,必须每行一个名字。接着使用random模块进行随机抽取。最后,通过Tkinter库的ScrolledText控件一次性输出抽奖结果。 其中,random模块是实现抽奖功能的核心,该模块提供了生成随机数和从序列中随机选择元素的函数。

该抽奖程序主要包括两个核心窗口页面,分别是抽奖的主窗口和奖项设置窗口,在Tkinter应用程序的主窗口里,可以通过“设置奖项”按钮打开奖项设置窗口,在弹出的输入框中自定义输入“奖项名称”和“获奖人数”,比如,特等奖设定1名,一等奖设定2名,以此类推。每抽奖一次,剩余名单中将删除已中奖名单,确保不重复中奖。

2、抽奖程序界面演示

Python中基于Tkinter设计抽奖程序

Python中基于Tkinter设计抽奖程序

3、代码实现

(1)导入必要的库

import random, webbrowser
import tkinter as tk
from tkinter import scrolledtext, messagebox, filedialog
import tkinter.font as tkFont

这里导入了Tkinter库用于创建GUI应用图形界面,Tkinter的messagebox用于消息提示,scrolledtext‌用于创建带有滚动条的文本框控件,Tkinter的filedialog模块提供了一个简单的对话框界面,可以让用户选择文件或文件夹。random库Python的一个标准库,用于生成随机数、随机整数、还可以从序列中随机选择数据,random库适用于随机性的运用场景,如模拟、游戏开发、算法测试等。Python的webbrowser库能够调用系统的默认浏览器或指定浏览器,打开指定的URL或本地的HTML文件。

(2)抽奖程序的完整代码如下所示:

动手练一练:

import random, webbrowser
import tkinter as tk
from tkinter import scrolledtext, messagebox, filedialog
import tkinter.font as tkFont

# 定义PrizeDraw类
class PrizeDraw:
    def __init__(self, members, prizes):
        # 初始化抽奖系统
        # 获取成员名单
        self.members = members.copy()
        # 奖项设置,prizes是字典,格式为 {奖项名称: 奖品数量}
        self.prizes = prizes
        # 定义空字典,用于存储中奖记录
        self.winners = {}

    # 定义一轮抽奖函数
    def draw(self, award_name):
        # 判断奖项名称是否存在
        if award_name not in self.prizes:
            raise ValueError(f"未找到奖项:{award_name}")

        # 根据奖项名称获取奖品数量
        winners_number = self.prizes[award_name]

        # 如果奖品数量大于成员数量,则抛出错误
        if winners_number > len(self.members):
            raise ValueError(f"奖品数量({winners_number})超过剩余参与人数({len(self.members)})")

        # 中奖者初始定义为空
        winners = []

        # 追加中奖者名单
        for i in range(winners_number):
            winner = random.choice(self.members)
            winners.append(winner)
            # 剩余名单中删除已中奖名单,确保不重复中奖
            self.members.remove(winner)
        self.winners[award_name] = winners

        # 返回本轮中奖者名单
        return winners

    # 输出所有中奖结果
    def display_results(self):
        # 设置允许修改输出框
        result_name.config(state=tk.NORMAL)
        result_name.insert(tk.END, f"========= 抽奖结果 =========" + "\n")
        for prize, winners in self.winners.items():
            result_name.insert(tk.END, f"{prize}获得者:" + "\n")
            for winner in winners:
                result_name.insert(tk.END, f"{winner}" + "\n")

# 抽奖主函数
def main():
    # 判断是否已经设置奖项
    if not awards:
        messagebox.showerror('错误','当前奖项:未设置')
        return

    # 获取所有名字
    members = names_text.get("1.0", "end-1c").strip().split("\n")

    # 判断是否为空
    if len(members) < 1:
        messagebox.showerror("错误", "请输入至少一个名字!")
        return

    # 将awards列表字典转换成字典形式,格式为 {奖项名称: 奖品数量}
    prizes = {item['name']: item['quota'] for item in awards}

    # 创建抽奖系统
    prize_draw = PrizeDraw(members, prizes)

    # 遍历所有奖项,按顺序抽奖
    try:
        for key in prizes:
            prize_draw.draw(key)

        # 最终显示结果
        prize_draw.display_results()
    except Exception as e:
        messagebox.showerror("错误", f"抽奖过程出错:{str(e)}")

# “奖项”设置窗口
def manage_awards():
    award_window = tk.Toplevel(app)
    award_window.title("奖项管理")

    # 设置窗口居中
    window_width = 400
    window_height = 380
    screen_width = award_window.winfo_screenwidth()
    screen_height = award_window.winfo_screenheight()
    x = (screen_width - window_width) / 2
    y = (screen_height - window_height) / 2
    award_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
    award_window.resizable(width=False, height=False)

    # 创建“奖项名称”和“获奖人数”输入框,完全可以自定义输入
    tk.Label(award_window, text="奖项名称:").grid(row=0, column=0, padx=10, pady=10, sticky="e")
    name_entry = tk.Entry(award_window)
    name_entry.grid(row=0, column=1, padx=10, pady=10, sticky="w")
    tk.Label(award_window, text="获奖人数:").grid(row=1, column=0, padx=10, pady=10, sticky="e")
    count_entry = tk.Entry(award_window)
    count_entry.grid(row=1, column=1, padx=10, pady=10, sticky="w")

    # 将“奖项名称”和“获奖人数”追加到awards列表字典中
    def prize_add():
        name = name_entry.get().strip()
        counts = count_entry.get().strip()
        if not name:
            messagebox.showerror("错误", "奖项名称不能为空")
            return
        try:
            count = int(counts)
            if count <= 0:
                raise ValueError
        except ValueError:
            messagebox.showerror("错误", "请输入有效的正整数")
            return
        if any(award["name"] == name for award in awards):
            messagebox.showerror("错误", "该奖项名称已存在")
            return
        awards.append({
            "name": name,
            "quota": count,
        })
        update_listbox()
        name_entry.delete(0, tk.END)
        count_entry.delete(0, tk.END)

    # 删除已设定的“奖项名称”和“获奖人数”
    def delete_award():
        selected = listbox.curselection()
        if not selected:
            messagebox.showwarning("警告", "请先选择奖项再删除")
            return
        index = selected[0]
        del awards[index]
        update_listbox()

    # 定义退出函数
    def user_quit():
        award_window.destroy()

    add_btn = tk.Button(award_window, text="添加奖项并保存", command=prize_add)
    add_btn.grid(row=2, columnspan=2, padx=10, pady=10)

    listbox = tk.Listbox(award_window, width=50)
    listbox.grid(row=3, columnspan=2, padx=10, pady=5)

    del_btn = tk.Button(award_window, text="删除选中奖项", command=delete_award)
    del_btn.grid(row=4, column=0, padx=10, pady=5, sticky="e")

    # 创建“确认设置”按钮
    quit_button = tk.Button(award_window,text='确认设置', command=user_quit)
    quit_button.grid(row=4, column=1, padx=10, pady=5)

    # 将已设置的结果追加到listbox控件中显示
    def update_listbox():
        listbox.delete(0, tk.END)
        for award in awards:
            listbox.insert(tk.END, f"{award['name']} - {award['quota']}人")
    update_listbox()
    award_window.transient(app)
    award_window.grab_set()
    app.wait_window(award_window)

# 保存抽奖结果到本地的txt文件内
def save_result():
    # 创建一个文件对话框来选择文件保存的位置
    save_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
    if save_path:
        # 获取ScrolledText的内容
        content = result_name.get(1.0, tk.END)
        # 写入文件
        with open(save_path, "w") as file:
            file.write(content)

# 清除所有的抽奖结果
def clear_result():
    # 允许修改输出框
    result_name.config(state=tk.NORMAL)
    # 定义清除文本的功能
    result_name.delete(1.0, tk.END)

# 设置页面的复位函数
def reset_setting_command():
    # 清空名单
    names_text.delete("1.0", tk.END)
    # 清空“奖项”设置
    awards.clear()
    clear_result()

# 程序讲解页面
def help_window():
    webbrowser.open("https://www.pyhint.com/article/151.html")

# 关于程序页面
def program_about():
    about = tk.Tk()
    about.title('关于程序')

    # 设置窗口居中
    window_width = 320
    window_height = 320
    screen_width = about.winfo_screenwidth()
    screen_height = about.winfo_screenheight()
    x = (screen_width - window_width) / 2
    y = (screen_height - window_height) / 2
    about.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
    about.resizable(width=False, height=False)

    about_frame = tk.Frame(about, width=320, height=320)
    about_frame.pack()
    about_font_1 = tkFont.Font(family='宋体', size=16, weight=tkFont.BOLD)
    tk.Label(about_frame, text='抽奖系统', font=about_font_1).place(x=120, y=20)
    tk.Label(about_frame, text='使用编程语言:Python', font=about_font_1).place(x=50, y=90)
    tk.Label(about_frame, text='导入名单方式:直接输入名单', font=about_font_1).place(x=50, y=150)
    tk.Label(about_frame, text='保存中奖名单方式:txt文件保存', font=about_font_1).place(x=50, y=210)
    tk.Label(about_frame, text='创作者:www.pyhint.com', font=about_font_1).place(x=50, y=270)
    about.mainloop()

# 当前模块直接被执行
if __name__ == "__main__":
    # 创建Tkinter窗口
    app = tk.Tk()
    app.title("抽奖工具")
    menu_bar = tk.Menu(app)
    file_menu = tk.Menu(menu_bar, tearoff=0)
    file_menu.add_command(label="关于程序", command=program_about)
    file_menu.add_command(label="程序讲解", command=help_window)
    file_menu.add_separator()  
    file_menu.add_command(label="退出", command=app.quit)
    menu_bar.add_cascade(label="帮助", menu=file_menu)
    settings_menu = tk.Menu(menu_bar, tearoff=0)
    settings_menu.add_command(label="管理奖项", command=manage_awards)
    settings_menu.add_command(label="复位", command=reset_setting_command)
    menu_bar.add_cascade(label="设置", menu=settings_menu)
    app.config(menu=menu_bar)
    awards = []

    # 设置窗口居中
    window_width = 400
    window_height = 620
    screen_width = app.winfo_screenwidth()
    screen_height = app.winfo_screenheight()
    x = (screen_width - window_width) / 2
    y = (screen_height - window_height) / 2
    app.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
    app.resizable(width=False, height=False)

    # 创建抽奖名单输入框
    all_label = tk.Label(app, text="请输入抽奖名单,每行一个名字:")
    all_label.pack(pady=5)
    names_text = scrolledtext.ScrolledText(app, width=50, height=15)
    names_text.pack(pady=5)

    # 在ScrolledText控件中插入默认文本
    names_text.insert(tk.END, "张三\n李四\n王五\n赵六\n钱七\n孙八\n周九\n吴十")

    # 创建按钮容器
    Button_frame = tk.Frame(app)
    Button_frame.pack(pady=5)

    # 创建“设置奖项”按钮
    settings_Button = tk.Button(Button_frame, text="设置奖项", font=('黑体', 15), command=manage_awards, width=10, height=1)
    settings_Button.pack(padx=10, pady=10, side=tk.LEFT)

    # 创建“开始抽奖”按钮
    confirm_button = tk.Button(Button_frame, text="开始抽奖", font=('黑体', 15), command=main, width=10, height=1)
    confirm_button.pack(padx=10, pady=10, side=tk.RIGHT)

    # 创建“抽奖结果”输出框
    result_label = tk.Label(app, text="抽奖结果:")
    result_label.pack(pady=5)

    result_name = scrolledtext.ScrolledText(app, width=50, height=15, wrap=tk.WORD, state=tk.DISABLED)
    result_name.pack(pady=5)

    # 创建按钮容器
    result_frame = tk.Frame(app)
    result_frame.pack(pady=5)

    # 左边创建一个按钮来触发“保存抽奖结果”操作
    save_button = tk.Button(result_frame, text="保存抽奖结果", font=('黑体', 15), command=save_result, width=15, height=1)
    save_button.pack(padx=10, pady=10, side=tk.LEFT)

    # 右边创建“清除抽奖结果”按钮并绑定到clear_result函数
    clear_button = tk.Button(result_frame, text="清除抽奖结果", font=('黑体', 15), command=clear_result, width=15, height=1)
    clear_button.pack(padx=10, pady=10, side=tk.RIGHT)

    # 开启主循环,让窗口处于显示状态
    app.mainloop()