一、前言需求背景描述

前面我编写了一段能生成随机幸运号码的代码,但是并不实用,每次去买颜色艳丽的票之前都需要在PyCharm上运行并将幸运号码在控制台打印出来

为解决这个问题,尝试使用Python的ttkbootstrap实现简单的号码展示,并根据当前日期展现对应类型(超级彩票、彩色球票)的幸运号码,达到动态展示的效果

二、窗口元素创建配置

ttkbootstrap是基于Python自带的tkinter的界面美化库,基本属性配置使用和tkinter没有太大差别,故使用ttkbootstrap库来开发生成器的界面,因其是第三方库,这里需要先安装

pip install ttkbootstrap

未方便后续调优,创建了GUI类,先初始化,再创建页面元素,使用Label展示内容即可

窗口的主题themename以及控件的bootstyle设置参考ttkbootstrap官网:暗色主题

随机幸运号码自动生成器之Python宝典【上】_GUI界面

示例代码:

import ttkbootstrap as ttk
from ttkbootstrap.constants import *


class GUI:

    def __init__(self, master):
        """Winning_Ticket GUI"""
        self.root = master
        self.create_page()  # 显示页面元素

    def create_page(self):
        """创建页面元素"""
        # 幸运号码标签
        self.winning_ticket_label = ttk.Label(self.root, text='幸运号码第一注\n幸运号码第二注', bootstyle=SUCCESS)  # 创建Label
        self.winning_ticket_label.pack()  # pack布局方式


if __name__ == "__main__":
    root = ttk.Window(themename="cyborg")  # 创建窗口,设置主题
    GUI(root)  # 展示GUI界面
    root.mainloop()  # 进入消息循环

运行效果:

随机幸运号码自动生成器之Python宝典【上】_浮动窗口_02

三、Label基础属性配置

在GUI类中新建一个方法show_winning_ticket,使用config来设置Label的文本内容和字体

注意:需要在初始化方法中调用show_winning_ticket方法

def show_winning_ticket(self):
    """
    展示幸运号码
    """
    winning_ticket = '幸运号码第一注\n幸运号码第二注'
    self.winning_ticket_label.config(text=winning_ticket, font=("Times New Roman", 20, 'bold'))  # 设置幸运号码标签显示内容

运行效果:

随机幸运号码自动生成器之Python宝典【上】_浮动窗口_03

四、幸运号码展示机制

先获取当前的日期、星期和时间,星期用于判断幸运号码类型,日期和时间展示用

def date_time_handle():
    week_list = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]  # week列表
    date_today = datetime.date.today()  # 今天的日期
    today_week_num = datetime.date.isoweekday(date_today)  # 今天星期数(星期一:1,星期日:7)
    week_today = week_list[today_week_num - 1]  # 今天周几
    current_time = datetime.datetime.now().strftime("%H:%M:%S")  # 当前时间
    return date_today, [week_today, today_week_num], current_time

再根据当前实际的星期,调用之前的生成随机幸运号码方法,展示对应类型的号码:星期1、3、6--超级彩票;星期2、4、7--彩色球票

def show_winning_ticket(self):
    """
    展示幸运号码
    """
    date_today, week_list, current_time = date_time_handle()  # 获取日期和时间
    if week_list[1] in (1, 3, 6):  # 周一、周三、周六
        winning_ticket = '\n'.join(generate_winning_ticket(0, 2))  # 生成两注超级彩票号码
    elif week_list[1] in (2, 4, 7):  # 周二、周四、周日
        winning_ticket = '\n'.join(generate_winning_ticket(1, 2))  # 生成两注彩色球票号码
    else:
        winning_ticket = '咱周五不说事儿'
    self.winning_ticket_label.config(text=winning_ticket, font=("Times New Roman", 20, 'bold'))  # 设置幸运号码标签显示内容

运行效果:

随机幸运号码自动生成器之Python宝典【上】_GUI界面_04

随机幸运号码自动生成器之Python宝典【上】_ttkbootstrap_05

随机幸运号码自动生成器之Python宝典【上】_ttkbootstrap_06

五、时间动态更新机制

在create_page方法中添加日期和时间标签,布局于幸运号码的上方

def create_page(self):
    """创建页面元素"""
    # 日期标签
    self.date_label = ttk.Label(self.root, font=("Times New Roman", 20), bootstyle=PRIMARY)  # 创建Label
    self.date_label.pack()  # 使用pack布局方式
    # 时间标签
    self.time_label = ttk.Label(self.root, font=("Times New Roman", 20), bootstyle=PRIMARY)  # 创建Label
    self.time_label.pack()
    # 幸运号码标签
    self.winning_ticket_label = ttk.Label(self.root, bootstyle=SUCCESS)  # 创建Label
    self.winning_ticket_label.pack()  # pack布局方式

再新建update_date_time方法,设置标签展示内容,并使用after每隔1s动态更新时间

注意:需要在初始化方法中调用update_date_time方法

def update_date_time(self):
    """
    更新日期和时间
    """
    date_today, week_list, current_time = date_time_handle()  # 获取日期和时间
    date_content = date_today.strftime("%Y年%m月%d日")  # 格式化今天的日期
    time_content = f"{week_list[0]} {current_time}"  # 格式化星期和时间
    self.date_label.config(text=date_content)  # 设置日期标签显示内容
    self.time_label.config(text=time_content)  # 设置时间标签显示内容
    self.time_label.after(1000, self.update_date_time)  # 每隔1s更新时间

运行效果:

随机幸运号码自动生成器之Python宝典【上】_浮动窗口_07

随机幸运号码自动生成器之Python宝典【上】_Python_08

六、窗口优化属性设置

幸运号码、日期时间已经展示在窗口上,可是我觉得窗口并不美观:

1.窗口总是出现在屏幕最上角---->设置出现在屏幕中间

2.窗口可被其他应用遮挡,未置于顶层---->设置总是处于顶层

3.边框与主题样式不匹配---->去除边框

4.可最大最小化以及调整窗口大小---->设置为工具窗口

注意:窗口属性在实例化后的window中设置即可

# --------【窗口优化属性设置】-------
root.wm_attributes("-topmost", True)  # 窗口处于顶层
root.overrideredirect(True)  # 去除窗口边框
root.wm_attributes("-toolwindow", True)  # 设置为工具窗口(无关闭、最大最小化窗口按钮)
root.place_window_center()  # 设置窗口居中
# --------【窗口优化属性设置】-------

运行效果:

随机幸运号码自动生成器之Python宝典【上】_Python_09

七、按键事件绑定配置

在优化了窗口之后,发现因为设置了工具窗口(没有最大最小化以及关闭按钮),使得窗口无法被移动和关闭,想到的解决办法是:

1.绑定鼠标按键事件,通过鼠标拖动窗口

2.绑定键盘按键事件,按下Alt+q时关闭窗口

第一步需要先创建鼠标及键盘对应的事件函数

def mouse_press_l(e):
    """
    按下鼠标左键设置坐标
    """
    global x, y
    x = e.x
    y = e.y


def mouse_release_l(e):
    """
    松开鼠标左键时坐标清除坐标
    """
    global x, y
    x = None
    y = None


def mouse_move_l(e):
    """
    按下鼠标左键拖动时更新窗口坐标
    """
    global x, y
    x_offset = e.x - x
    y_offset = e.y - y
    root.geometry("+%s+%s" % (root.winfo_x() + x_offset, root.winfo_y() + y_offset))
    root.update()


def _quit(*args):
    """
    关闭窗口
    """
    root.destroy()

第二步将上面的事件函数与窗口的按键操作监听绑定起来

# --------【按键事件绑定配置】-------
root.bind("<ButtonPress-1>", mouse_press_l)  # 绑定按下左键时的响应函数
root.bind("<ButtonRelease-1>", mouse_release_l)  # 绑定左键松开时的响应函数
root.bind("<B1-Motion>", mouse_move_l)  # 绑定鼠标移动时的响应函数
root.bind("<Alt q>", _quit)  # 绑定按下Alt+q时销毁窗口
# --------【按键事件绑定配置】-------

运行效果:

随机幸运号码自动生成器之Python宝典【上】_GUI界面_10

八、结语附加完整代码

经过一系列的代码实现,我们已经成功开发了一个能够展示幸运号码并且能够动态显示当前时间的浮动小工具。然而,该软件目前仍需依赖Python运行环境,并且不能自动运行,需要人为手动启动。为了解决上述问题,我们将在下一篇文章中介绍如何快速打包成可执行的exe程序,并且实现自动在windows上运行的功能

完整代码:

import datetime
import random
import ttkbootstrap as ttk
from ttkbootstrap.constants import *

global x, y


class GUI:

    def __init__(self, master):
        """Winning_Ticket GUI"""
        self.root = master
        self.create_page()  # 显示页面元素
        self.show_winning_ticket()  # 显示幸运号码
        self.update_date_time()  # 显示日期和时间

    def create_page(self):
        """创建页面元素"""
        # 日期标签
        self.date_label = ttk.Label(self.root, font=("Times New Roman", 20), bootstyle=PRIMARY)  # 创建Label
        self.date_label.pack()  # 使用pack布局方式
        # 时间标签
        self.time_label = ttk.Label(self.root, font=("Times New Roman", 20), bootstyle=PRIMARY)  # 创建Label
        self.time_label.pack()
        # 幸运号码标签
        self.winning_ticket_label = ttk.Label(self.root, bootstyle=SUCCESS)  # 创建Label
        self.winning_ticket_label.pack()  # pack布局方式

    def show_winning_ticket(self):
        """
        展示幸运号码
        """
        date_today, week_list, current_time = date_time_handle()  # 获取日期和时间
        if week_list[1] in (1, 3, 6):  # 周一、周三、周六
            winning_ticket = '\n'.join(generate_winning_ticket(0, 2))  # 生成两注超级彩票号码
        elif week_list[1] in (2, 4, 7):  # 周二、周四、周日
            winning_ticket = '\n'.join(generate_winning_ticket(1, 2))  # 生成两注彩色球票号码
        else:
            winning_ticket = '咱周五不说事儿'
        self.winning_ticket_label.config(text=winning_ticket, font=("Times New Roman", 20, 'bold'))  # 设置幸运号码标签显示内容

    def update_date_time(self):
        """
        更新日期和时间
        """
        date_today, week_list, current_time = date_time_handle()  # 获取日期和时间
        date_content = date_today.strftime("%Y年%m月%d日")  # 格式化今天的日期
        time_content = f"{week_list[0]} {current_time}"  # 格式化星期和时间
        self.date_label.config(text=date_content)  # 设置日期标签显示内容
        self.time_label.config(text=time_content)  # 设置时间标签显示内容
        self.time_label.after(1000, self.update_date_time)  # 每隔1s更新时间


def date_time_handle():
    week_list = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]  # week列表
    date_today = datetime.date.today()  # 今天的日期
    today_week_num = datetime.date.isoweekday(date_today)  # 今天星期数(星期一:1,星期日:7)
    week_today = week_list[today_week_num - 1]  # 今天周几
    current_time = datetime.datetime.now().strftime("%H:%M:%S")  # 当前时间
    return date_today, [week_today, today_week_num], current_time


def generate_lucky_num(lucky_range: int, lucky_num: int):
    """
    生成随机幸运号码
    :param lucky_range: 幸运数字范围
    :param lucky_num: 幸运数字数量
    :return:
    """
    ran_list = random.sample([i + 1 for i in range(lucky_range)], lucky_num)  # 在1-lucky_range范围内随机生成lucky_num个数字
    ran_list.sort()  # 从小到大排序
    lucky_num_list = [str(i).zfill(2) for i in ran_list]  # 转换为字符串并添加前导0
    return lucky_num_list


def generate_winning_ticket(ticket_type: int, ticket_num: int):
    """
    生成号码
    :param ticket_type: 类型(超级彩票--0;彩色球票--1)
    :param ticket_num: 数量
    :return:
    """
    tickets = []  # 定义彩票号码列表
    for n in range(ticket_num):  # 遍历彩票数量
        # 超级彩票
        if ticket_type == 0:
            front_section = generate_lucky_num(35, 5)  # 前区号码
            back_section = generate_lucky_num(12, 2)  # 后区号码
        # 彩色球票
        elif ticket_type == 1:
            front_section = generate_lucky_num(33, 6)  # 前区号码
            back_section = generate_lucky_num(16, 1)  # 后区号码
        # 其他
        else:
            return "无效的彩票类型(超级彩票--0;彩色球票--1)"
        tickets.append(" ".join(front_section + ["+"] + back_section))  # 拼接号码
    return tickets


def mouse_press_l(e):
    """
    按下鼠标左键设置坐标
    """
    global x, y
    x = e.x
    y = e.y


def mouse_release_l(e):
    """
    松开鼠标左键时坐标清除坐标
    """
    global x, y
    x = None
    y = None


def mouse_move_l(e):
    """
    按下鼠标左键拖动时更新窗口坐标
    """
    global x, y
    x_offset = e.x - x
    y_offset = e.y - y
    root.geometry("+%s+%s" % (root.winfo_x() + x_offset, root.winfo_y() + y_offset))
    root.update()


def _quit(*args):
    """
    关闭窗口
    """
    root.destroy()


if __name__ == "__main__":
    root = ttk.Window(themename="cyborg")  # 创建窗口,设置主题
    root.wm_attributes("-topmost", True)  # 窗口处于顶层
    root.overrideredirect(True)  # 去除窗口边框
    root.wm_attributes("-toolwindow", True)  # 设置为工具窗口(无关闭、最大最小化窗口按钮)
    root.place_window_center()  # 设置窗口居中
    root.bind("<ButtonPress-1>", mouse_press_l)  # 绑定按下左键时的响应函数
    root.bind("<ButtonRelease-1>", mouse_release_l)  # 绑定左键松开时的响应函数
    root.bind("<B1-Motion>", mouse_move_l)  # 绑定鼠标移动时的响应函数
    root.bind("<Alt q>", _quit)  # 绑定按下Alt+q时销毁窗口
    GUI(root)  # 展示GUI界面
    root.mainloop()  # 进入消息循环