Bootstrap SomeTools Icon
返回
import tkinter as tk
import random
import threading
import time


class StandaloneToast:
    def __init__(self, message, toast_type="style_1",
                 position=None, duration=4000):
        self.message = message
        self.toast_type = toast_type
        self.position = position
        self.duration = duration

        # 在新线程中启动 GUI
        self.thread = threading.Thread(target=self.create_toast, daemon=True)
        self.thread.start()

    def create_toast(self):
        try:
            # 创建根窗口但不显示主窗口
            self.root = tk.Tk()
            self.root.withdraw()  # 隐藏主窗口

            # 创建 Toast 窗口
            self.toast = tk.Toplevel(self.root)
            self.setup_toast_window()

            # 这一行控制的是弹窗自动关闭
            # self.root.after(self.duration, self.fade_out)

            self.root.mainloop()
        except Exception as e:
            print(f"Toast创建错误: {e}")
        finally:
            # 确保资源被清理
            if hasattr(self, 'root'):
                try:
                    self.root.quit()
                    self.root.destroy()
                except:
                    pass

    def setup_toast_window(self):
        self.toast.overrideredirect(True)  # 无标题栏
        self.toast.attributes('-alpha', 0.0)  # 初始透明
        self.toast.attributes('-topmost', True)

        # 样式配置
        styles = {
            "style_1": {"bg": "#d4edda", "fg": "#155724", "icon": "@"},
            "style_2": {"bg": "#f8d7da", "fg": "#721c24", "icon": "#"},
            "style_3": {"bg": "#fff3cd", "fg": "#856404", "icon": "$"},
            "style_4": {"bg": "#d1ecf1", "fg": "#0c5460", "icon": "%"}
        }

        style = styles.get(self.toast_type, styles["style_1"])

        # 创建内容框架
        frame = tk.Frame(
            self.toast,
            bg=style["bg"],
            relief='solid',
            borderwidth=1
        )
        frame.pack(padx=1, pady=1)

        # 图标
        icon_label = tk.Label(
            frame,
            text=style["icon"],
            bg=style["bg"],
            fg=style["fg"],
            font=("Arial", 12, "bold")
        )
        icon_label.pack(side=tk.LEFT, padx=(10, 5), pady=10)

        # 消息
        message_label = tk.Label(
            frame,
            text=self.message,
            bg=style["bg"],
            fg=style["fg"],
            font=("微软雅黑", 9)
        )
        message_label.pack(side=tk.LEFT, padx=(0, 15), pady=10)

        # 设置位置和大小
        self.set_position()

        # 淡入动画
        self.fade_in()

    def set_position(self):
        self.toast.update_idletasks()

        if self.position:
            x, y = self.position
        else:
            screen_width = self.toast.winfo_screenwidth()
            screen_height = self.toast.winfo_screenheight()
            x = random.randint(100, screen_width - 200)
            y = random.randint(100, screen_height - 100)
        self.toast.geometry(f"+{x}+{y}")

    def fade_in(self):
        # 淡入动画
        alpha = 0.0

        def increase_alpha():
            nonlocal alpha
            alpha += 0.1
            self.toast.attributes('-alpha', alpha)
            if alpha < 0.95:
                self.toast.after(40, increase_alpha)

        increase_alpha()

    def fade_out(self):
        # 淡出动画并关闭
        alpha = 0.95

        def decrease_alpha():
            nonlocal alpha
            alpha -= 0.1
            self.toast.attributes('-alpha', alpha)
            if alpha > 0:
                self.toast.after(40, decrease_alpha)
            else:
                self.toast.destroy()
                self.root.quit()
                self.root.destroy()

        decrease_alpha()

    def wait_for_completion(self):
        if hasattr(self, 'thread'):
            self.thread.join()


class ToastManager:
    def __init__(self):
        self.active_toasts = []

    def show_toast(self, message, toast_type="style_1", position=None, duration=4000):
        toast = StandaloneToast(message, toast_type, position, duration)
        self.active_toasts.append(toast)
        return toast

    def show_multiple_toasts(self, toast_configs, delay=0):
        def show_sequential():
            for config in toast_configs:
                self.show_toast(**config)
                time.sleep(delay)

        threading.Thread(target=show_sequential, daemon=True).start()


def show_toasts_with_interval(thread_name, count=40):
    style_list = ["style_1", "style_2", "style_3", "style_4"]
    messages = ["考试通过", "暴富", "天天开心", "梦想成真", "工作顺利", "岁岁平安"]

    for i in range(count):
        try:
            StandaloneToast(
                f"{random.choice(messages)}",
                # f"{thread_name} - {random.choice(messages)} ({i + 1}/{count})",
                random.choice(style_list),
                duration=4000  # 4秒后关闭
            )
            # 固定间隔0.5秒
            time.sleep(0.4)

        except Exception as e:
            print(f"线程 {thread_name} 第 {i + 1} 次执行出错: {e}")


def main_multi_thread():
    thread_names = ["线程1", "线程2", "线程3"]
    threads = []

    for thread_name in thread_names:
        thread = threading.Thread(
            target=show_toasts_with_interval,
            args=(thread_name, 40),  # 每个线程显示20个弹窗
            daemon=True
        )
        threads.append(thread)
        thread.start()
        print(f"启动 {thread_name}")
        time.sleep(0.2)  # 稍微错开线程启动时间

    # 计算预计完成时间用于缓冲
    total_time = 40 * 0.4 + 4
    # 等待所有线程完成
    for i, thread in enumerate(threads):
        thread.join(timeout=total_time + 3)  # 额外缓冲时间


if __name__ == "__main__":
    main_multi_thread()