Bootstrap

python实现应用多开工具v1.0,写着玩

python实现应用多开工具v1.0,写着玩

一款简洁实用的Windows应用多开工具,别支持微信多开!告别切换账号的烦恼,轻松管理多个应用实例。 不做别的用处,只是来学习


【应用多开启动器 V1.0】

在这里插入图片描述


用到的库:

pip install pyinstaller
pip install pywin32

✨ 主要特性:
• 支持微信等应用的多开功能
• 简洁美观的图形界面
• 便捷的应用管理(添加/编辑/删除)
• 支持应用快速搜索
• 支持应用分类管理
• 支持拖拽添加应用(实现不太友好,所以还是没有做)
• 右键快捷菜单操作

🎯 使用方法:

  1. 点击"添加应用",输入应用名称和路径
  2. 选择需要启动的应用,点击"启动实例"
  3. 支持双击编辑应用信息
  4. 可通过搜索框快速查找应用

⚡️ 特别说明:
• 完全免费开源
• 界面清爽,操作简单
• 支持文件拖放,快速添加应用
• 配置数据本地保存,重启不丢失

在这里插入图片描述
百度网盘:https://pan.baidu.com/s/1ib0-QU30ElFI9lCX7M_eOQ
提取码: 6666

源码:

import pyperclip
import time
from collections import deque
import tkinter as tk
from tkinter import scrolledtext, messagebox, ttk
from PIL import Image, ImageTk
import io
import threading
import win32clipboard
from io import BytesIO

class ClipboardManager:
    def __init__(self, max_history=50):
        self.history = deque(maxlen=max_history)
        self.running = True
        self.last_value = ""
        self.callbacks = []  # 添加回调函数列表用于通知GUI更新

    def start_monitoring(self):
        while self.running:
            try:
                # 检查剪贴板内容类型
                if self.is_image_in_clipboard():
                    image_data = self.get_image_from_clipboard()
                    if image_data and image_data != self.last_value:
                        self.history.append(("image", image_data))
                        self.last_value = image_data
                else:
                    current_value = pyperclip.paste()
                    if current_value != self.last_value and current_value.strip():
                        self.history.append(("text", current_value))
                        self.last_value = current_value
                
                # 通知所有观察者更新
                self.notify_observers()
                
            except Exception as e:
                print(f"监控剪贴板时出错: {str(e)}")
            time.sleep(0.5)

    def is_image_in_clipboard(self):
        try:
            win32clipboard.OpenClipboard()
            format_id = win32clipboard.EnumClipboardFormats(0)
            while format_id:
                if format_id == win32clipboard.CF_DIB:
                    win32clipboard.CloseClipboard()
                    return True
                format_id = win32clipboard.EnumClipboardFormats(format_id)
            win32clipboard.CloseClipboard()
        except:
            pass
        return False

    def get_image_from_clipboard(self):
        try:
            win32clipboard.OpenClipboard()
            if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB):
                data = win32clipboard.GetClipboardData(win32clipboard.CF_DIB)
                win32clipboard.CloseClipboard()
                return data
            win32clipboard.CloseClipboard()
        except:
            pass
        return None

    def add_observer(self, callback):
        self.callbacks.append(callback)

    def notify_observers(self):
        for callback in self.callbacks:
            callback()

    def get_history(self):
        return list(self.history)

    def search_history(self, keyword):
        return [item for item in self.history if keyword.lower() in item.lower()]

    def clear_history(self):
        self.history.clear()

class ClipboardManagerGUI:
    def __init__(self, manager):
        self.manager = manager
        self.root = tk.Tk()
        self.root.title("增强型剪贴板管理器-木木iOS分享制作")
        self.root.geometry("600x900")
        
        # 设置主题样式
        self.style = ttk.Style()
        self.style.theme_use('clam')
        
        # 自定义样式
        self.configure_styles()
        
        self.create_widgets()
        self.manager.add_observer(self.update_history)
        self.start_monitoring_thread()

    def configure_styles(self):
        """配置自定义样式"""
        # 更新颜色方案
        colors = {
            'search': {
                'normal': "#2196F3",  # 蓝色
                'hover': "#1976D2",   # 深蓝
                'pressed': "#0D47A1"  # 更深的蓝
            },
            'image': {
                'normal': "#4CAF50",  # 绿色
                'hover': "#388E3C",   # 深绿
                'pressed': "#1B5E20"  # 更深的绿
            },
            'clear': {
                'normal': "#F44336",  # 红色
                'hover': "#D32F2F",   # 深红
                'pressed': "#B71C1C"  # 更深的红
            }
        }
        
        bg_color = "#F5F5F5"  # 浅灰背景
        secondary_color = "#757575"  # 灰色
        
        # 配置根窗口
        self.root.configure(bg=bg_color)
        
        # 基础按钮样式
        button_base = {
            'padding': (15, 8),
            'relief': 'raised',
            'font': ("Microsoft YaHei UI", 9, "bold"),
            'borderwidth': 2
        }
        
        # 搜索按钮样式
        self.style.configure(
            "Search.TButton",
            **button_base,
            background=colors['search']['normal'],
            foreground="white"
        )
        self.style.map(
            "Search.TButton",
            background=[
                ("pressed", colors['search']['pressed']),
                ("active", colors['search']['hover'])
            ],
            relief=[("pressed", "sunken")]
        )
        
        # 图片历史按钮样式
        self.style.configure(
            "Image.TButton",
            **button_base,
            background=colors['image']['normal'],
            foreground="white"
        )
        self.style.map(
            "Image.TButton",
            background=[
                ("pressed", colors['image']['pressed']),
                ("active", colors['image']['hover'])
            ],
            relief=[("pressed", "sunken")]
        )
        
        # 清空按钮样式
        self.style.configure(
            "Clear.TButton",
            **button_base,
            background=colors['clear']['normal'],
            foreground="white"
        )
        self.style.map(
            "Clear.TButton",
            background=[
                ("pressed", colors['clear']['pressed']),
                ("active", colors['clear']['hover'])
            ],
            relief=[("pressed", "sunken")]
        )
        
        # 搜索框样式
        self.style.configure(
            "Custom.TEntry",
            padding=12,
            relief="solid",
            borderwidth=1,
            fieldbackground="white",
            font=("Microsoft YaHei UI", 10)
        )
        
        # 标签样式
        self.style.configure(
            "Custom.TLabel",
            font=("Microsoft YaHei UI", 9),
            background=bg_color,
            foreground=secondary_color
        )
        
        # 状态栏样式
        self.style.configure(
            "Status.TLabel",
            font=("Microsoft YaHei UI", 9),
            background="#E0E0E0",
            foreground=secondary_color,
            padding=5
        )

    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 标题
        title_frame = ttk.Frame(main_frame)
        title_frame.pack(fill=tk.X, pady=(0, 10))
        
        title_label = ttk.Label(
            title_frame, 
            text="智能剪贴板管理器", 
            font=("Microsoft YaHei UI", 16, "bold"),
            style="Custom.TLabel"
        )
        title_label.pack(side=tk.LEFT)

        # 搜索框和按钮组
        search_frame = ttk.Frame(main_frame)
        search_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 搜索框带图标
        search_container = ttk.Frame(search_frame)
        search_container.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        
        self.search_entry = ttk.Entry(
            search_container, 
            style="Custom.TEntry",
            font=("Microsoft YaHei UI", 9)
        )
        self.search_entry.pack(fill=tk.X, expand=True)
        self.search_entry.insert(0, "搜索历史记录...")
        self.search_entry.bind("<FocusIn>", self.on_entry_click)
        self.search_entry.bind("<FocusOut>", self.on_focus_out)
        
        # 按钮组
        button_frame = ttk.Frame(search_frame)
        button_frame.pack(side=tk.RIGHT)
        
        # 搜索按钮 - 蓝色
        ttk.Button(
            button_frame, 
            text="🔍 搜索", 
            style="Search.TButton",
            command=self.search_history
        ).pack(side=tk.LEFT, padx=4)
        
        # 图片历史按钮 - 绿色
        ttk.Button(
            button_frame, 
            text="🖼 图片历史", 
            style="Image.TButton",
            command=self.view_image_history
        ).pack(side=tk.LEFT, padx=4)
        
        # 清空历史按钮 - 红色
        ttk.Button(
            button_frame, 
            text="🗑 清空历史", 
            style="Clear.TButton",
            command=self.clear_history
        ).pack(side=tk.LEFT, padx=4)

        # 历史记录区域
        history_frame = ttk.Frame(main_frame, relief="solid", borderwidth=1)
        history_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        self.history_area = scrolledtext.ScrolledText(
            history_frame,
            font=("Microsoft YaHei UI", 10),
            wrap=tk.WORD,
            padx=10,
            pady=10,
            bg="white"
        )
        self.history_area.pack(fill=tk.BOTH, expand=True)

        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(
            main_frame,
            textvariable=self.status_var,
            style="Status.TLabel",
            anchor="w"
        )
        status_bar.pack(fill=tk.X)

    def start_monitoring_thread(self):
        monitor_thread = threading.Thread(target=self.manager.start_monitoring, daemon=True)
        monitor_thread.start()
        self.update_history()
        self.root.after(1000, self.periodic_update)  # 添加定期更新

    def periodic_update(self):
        """定期更新GUI"""
        try:
            self.update_history()
        except Exception as e:
            print(f"更新GUI时出错: {str(e)}")
        finally:
            self.root.after(1000, self.periodic_update)

    def update_history(self):
        """更新历史记录显示"""
        if not self.root:  # 检查窗口是否存在
            return
            
        self.history_area.delete(1.0, tk.END)
        history = self.manager.get_history()
        for item_type, content in history:
            if item_type == "text":
                self.history_area.insert(tk.END, f"{content}\n\n")
            elif item_type == "image":
                self.history_area.insert(tk.END, "[图片内容]\n\n")

    def view_image_history(self):
        """显示所有历史图片"""
        # 收集所有图片数据
        image_history = [(i, content) for i, (item_type, content) in enumerate(self.manager.get_history()) 
                        if item_type == "image"]
        
        if not image_history:
            messagebox.showinfo("提示", "剪贴板中没有图片记录")
            return

        # 美化图片查看窗口
        history_window = tk.Toplevel(self.root)
        history_window.title("图片历史记录")
        history_window.geometry("900x700")
        history_window.configure(bg="#F5F5F5")
        
        # 添加标题
        title_label = ttk.Label(
            history_window,
            text="图片历史记录",
            font=("Microsoft YaHei UI", 14, "bold"),
            style="Custom.TLabel"
        )
        title_label.pack(pady=10)

        # 创建滚动画布
        canvas = tk.Canvas(history_window, bg="#F5F5F5", highlightthickness=0)
        scrollbar = ttk.Scrollbar(history_window, orient="vertical", command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas, style="Custom.TFrame")

        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )

        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)

        # 显示所有图片
        for index, image_data in image_history:
            try:
                # 创建图片容器框架
                frame = ttk.Frame(scrollable_frame)
                frame.pack(pady=10, padx=10, fill=tk.X)

                # 添加图片序号标签
                ttk.Label(frame, text=f"图片 #{index + 1}").pack(pady=5)

                # 显示图片
                image = Image.open(BytesIO(image_data))
                # 调整图片大小
                image.thumbnail((400, 400))
                photo = ImageTk.PhotoImage(image)
                
                label = ttk.Label(frame, image=photo)
                label.image = photo  # 保持引用
                label.pack()

                # 使用绿色按钮样式
                ttk.Button(
                    frame, 
                    text="复制此图片", 
                    style="Image.TButton",
                    command=lambda img_data=image_data: self.copy_image_to_clipboard(img_data)
                ).pack(pady=5)
                
                # 添加分隔线
                ttk.Separator(scrollable_frame, orient='horizontal').pack(fill=tk.X, pady=5)

            except Exception as e:
                print(f"加载图片 #{index + 1} 时出错: {str(e)}")

        # 打包滚动组件
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    def copy_image_to_clipboard(self, image_data):
        """将选中的图片复制到剪贴板"""
        try:
            win32clipboard.OpenClipboard()
            win32clipboard.EmptyClipboard()
            win32clipboard.SetClipboardData(win32clipboard.CF_DIB, image_data)
            win32clipboard.CloseClipboard()
            self.status_var.set("图片已复制到剪贴板")
        except Exception as e:
            messagebox.showerror("错误", f"复制图片时出错: {str(e)}")
            self.status_var.set("复制图片失败")

    def search_history(self):
        keyword = self.search_entry.get()
        if keyword:
            results = self.manager.search_history(keyword)
            self.history_area.delete(1.0, tk.END)
            for item in results:
                self.history_area.insert(tk.END, item + "\n\n")

    def clear_history(self):
        self.manager.clear_history()
        self.history_area.delete(1.0, tk.END)
        messagebox.showinfo("提示", "历史记录已清空")

    def exit_program(self):
        self.manager.running = False
        self.root.destroy()

    def on_entry_click(self, event):
        """搜索框获得焦点时的处理"""
        if self.search_entry.get() == "搜索历史记录...":
            self.search_entry.delete(0, tk.END)
            self.search_entry.config(foreground="black")

    def on_focus_out(self, event):
        """搜索框失去焦点时的处理"""
        if not self.search_entry.get():
            self.search_entry.insert(0, "搜索历史记录...")
            self.search_entry.config(foreground="gray")

if __name__ == "__main__":
    try:
        manager = ClipboardManager()
        gui = ClipboardManagerGUI(manager)
        gui.root.mainloop()
    except Exception as e:
        messagebox.showerror("错误", f"程序启动失败: {str(e)}")
;