【2025年6月7日更新】 软件自选安装管理器

查看 230|回复 29
作者:114514csf   
   
软件自选安装管理器        下载地址
通过配置文件切换 主题颜色
[全局设置]
窗口标题 = 软件安装管理器
默认全选 = 是
主题 = 深色  #浅色
[软件列表]
腾讯QQ9.7纯净版 = qq.exe /S
微信电脑版 = WeChatWin.exe /S
Winrar压缩优化版 = WinRAR_v7.01_x64_SC.exe /S
2345看图王优化版 = 2345pic.exe /verysilent
2345拼音输入法优化版 = 2345pinyin.exe /quiet
搜狗拼音输入法优化版 = sogou.exe /S
装机人员维护工具箱 = toolkit.exe /install
爱奇艺优化版 = iqiyi.exe /silent
360安全卫士优化版 = 360safe.exe /S
360安全浏览器优化版 = 360browser.exe /verysilent

管理器, 软件, 拼音输入法

419545168   
   
# -*- coding: utf-8 -*-
import os
import configparser
import tkinter as tk
from tkinter import ttk, messagebox
import subprocess
import sys
import threading
import psutil
class SoftwareInstaller:
    def __init__(self, root):
        self.root = root
        self.root.title("软件安装管理器")
        self.root.geometry("750x500")
        self.root.resizable(False, False)
        # 初始化变量
        self.software_list = []
        self.install_commands = {}
        self.data_dir = os.path.join(os.path.dirname(sys.argv[0]), "data")
        self.window_title = "软件安装管理器"
        self.default_select_all = False
        self.theme = "浅色"  # 默认主题
        # 安装相关变量
        self.installation_processes = []
        self.failed_installations = []
        self.installation_complete = False
        self.progress_window = None
        # 检查并创建配置文件
        self.init_config_file()
        # 验证配置文件完整性
        if not self.verify_author_info():
            messagebox.showerror("启动失败", "文件被篡改,程序无法启动!")
            sys.exit()
        # 加载配置
        self.load_config()
        # 设置窗口居中
        self.center_window()
        # 设置样式(根据配置)
        self.setup_styles()
        # 创建界面
        self.create_widgets()
        # 加载软件列表
        self.load_software_list()
        self.populate_treeview()
    def verify_author_info(self):
        """验证程序信息部分是否被修改"""
        REQUIRED_AUTHOR_INFO = {
            '作者': '缘起性空',
            '版权': '版权所有 © 2025',
            '联系': '[email protected]'
        }
        if not os.path.exists('config.ini'):
            return False
        config = configparser.ConfigParser()
        config.read('config.ini', encoding='utf-8')
        if not config.has_section('程序信息'):
            return False
        for key, value in REQUIRED_AUTHOR_INFO.items():
            if not config.has_option('程序信息', key):
                return False
            if config.get('程序信息', key) != value:
                return False
        return True
    def init_config_file(self):
        """初始化配置文件"""
        if not os.path.exists('config.ini'):
            try:
                with open('config.ini', 'w', encoding='utf-8') as f:
                    f.write("""[程序信息]
作者 = 缘起性空
版权 = 版权所有 © 2025
联系 = [email protected]
[全局设置]
窗口标题 = 软件安装管理器
默认全选 = 否
主题 = 浅色  # 可选值:浅色/深色
[软件列表]
# 格式:软件名称 = 安装程序 参数
# 示例:
# 谷歌浏览器 = chrome_installer.exe /silent
# 微信办公版 = wechat_setup.exe /S
""")
                messagebox.showinfo("提示", "已创建默认配置文件 config.ini")
            except Exception as e:
                messagebox.showerror("错误", f"创建配置文件失败: {e}")
    def center_window(self):
        """使窗口居中显示"""
        self.root.update_idletasks()
        width = self.root.winfo_width()
        height = self.root.winfo_height()
        x = (self.root.winfo_screenwidth() // 2) - (width // 2)
        y = (self.root.winfo_screenheight() // 2) - (height // 2)
        self.root.geometry(f'+{x}+{y}')
    def load_config(self):
        """加载配置文件设置"""
        config = configparser.ConfigParser()
        try:
            if os.path.exists('config.ini'):
                config.read('config.ini', encoding='utf-8')
                # 读取窗口标题
                title = self.get_config_value(config, '全局设置', '窗口标题')
                if title:
                    self.window_title = title
                    self.root.title(self.window_title)
                # 读取默认全选设置
                select_all = self.get_config_value(config, '全局设置', '默认全选')
                if select_all:
                    select_all = select_all.strip().lower()
                    self.default_select_all = select_all in ('是', 'true', '1', 'yes', '开启', 'on')
                # 读取主题设置
                theme = self.get_config_value(config, '全局设置', '主题')
                if theme:
                    self.theme = theme.strip()
        except Exception as e:
            messagebox.showerror("配置错误", f"读取配置文件失败: {e}")
    def get_config_value(self, config, section, key):
        """安全获取配置值"""
        try:
            if section in config and key in config[section]:
                return config[section][key]
        except:
            pass
        return None
    def setup_styles(self):
        """根据主题配置设置样式"""
        self.style = ttk.Style()
        self.style.theme_use('clam')
        # 根据主题选择配色方案
        if self.theme == "深色":
            # 深色主题配色
            bg_color = "#2c3e50"      # 背景色
            text_color = "#ecf0f1"    # 文字颜色
            tree_bg = "#34495e"       # 表格背景
            button_bg = "#34495e"     # 按钮背景
            primary_color = "#3498db" # 主色
            secondary_color = "#2ecc71" # 辅助色
        else:
            # 浅色主题配色(默认)
            bg_color = "#f5f5f5"      # 背景色
            text_color = "#333333"    # 文字颜色
            tree_bg = "#ffffff"       # 表格背景
            button_bg = "#e0e0e0"     # 按钮背景
            primary_color = "#4a90e2" # 主色
            secondary_color = "#50c878" # 辅助色
        # 设置窗口背景
        self.root.configure(bg=bg_color)
        # 标题样式
        self.style.configure("Title.TLabel",
                           font=('Microsoft YaHei', 18, 'bold'),
                           background=bg_color,
                           foreground=text_color)
        # 表格样式
        self.style.configure("Treeview",
                           font=('Microsoft YaHei', 11),
                           rowheight=30,
                           background=tree_bg,
                           fieldbackground=tree_bg,
                           foreground=text_color,
                           bordercolor="#dddddd")
        # 表头样式(保持默认)
        self.style.configure("Treeview.Heading",
                           font=('Microsoft YaHei', 11, 'bold'),
                           relief="flat")
        # 选中行样式
        self.style.map("Treeview",
                      background=[('selected', primary_color)],
                      foreground=[('selected', 'white')])
        # 按钮样式
        self.style.configure("Exit.TButton",
                           background=button_bg,
                           foreground=text_color,
                           font=('Microsoft YaHei', 11),
                           padding=8)
        self.style.configure("Install.TButton",
                           background=secondary_color,
                           foreground="white",
                           font=('Microsoft YaHei', 11),
                           padding=8)
        # 按钮悬停效果
        hover_bg = "#3d566e" if self.theme == "深色" else "#e8e8e8"
        self.style.map("Exit.TButton",
                     background=[('active', hover_bg), ('pressed', '!disabled', button_bg)])
        self.style.map("Install.TButton",
                     background=[('active', '#60c080'), ('pressed', '!disabled', secondary_color)])
        # 进度条样式
        self.style.configure("Custom.Horizontal.TProgressbar",
                           background=primary_color,
                           troughcolor=button_bg,
                           thickness=20)
    def create_widgets(self):
        """创建界面组件"""
        # 获取当前主题的背景色
        bg_color = "#2c3e50" if self.theme == "深色" else "#f5f5f5"
        text_color = "#ecf0f1" if self.theme == "深色" else "#333333"
        # 标题区域
        title_frame = tk.Frame(self.root, bg=bg_color)
        title_frame.pack(pady=(20, 10))
        ttk.Label(title_frame, text=self.window_title, style="Title.TLabel").pack()
        # 表格区域
        tree_frame = tk.Frame(self.root, bg=bg_color)
        tree_frame.pack(fill=tk.BOTH, expand=True, padx=30, pady=(0, 15))
        # 创建Treeview
        self.tree = ttk.Treeview(
            tree_frame,
            columns=('选择', '序号', '软件名称', '软件大小'),
            show='headings',
            selectmode='none'
        )
        # 设置列
        columns = {
            '选择': {'width': 60, 'anchor': 'center'},
            '序号': {'width': 60, 'anchor': 'center'},
            '软件名称': {'width': 380, 'anchor': 'center'},
            '软件大小': {'width': 120, 'anchor': 'center'}
        }
        for col, opts in columns.items():
            self.tree.column(col, **opts)
            self.tree.heading(col, text=col)
        # 滚动条
        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        self.tree.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        # 绑定复选框点击事件
        self.tree.bind('[B]', self.on_tree_click)
        # 底部按钮区域
        bottom_frame = tk.Frame(self.root, bg=bg_color)
        bottom_frame.pack(fill=tk.X, padx=30, pady=(0, 20))
        # 左侧按钮区域(全选/反选)
        left_button_frame = tk.Frame(bottom_frame, bg=bg_color)
        left_button_frame.pack(side="left")
        # 全选/反选复选框
        self.select_all_var = tk.BooleanVar(value=self.default_select_all)
        select_all_cb = tk.Checkbutton(
            left_button_frame,
            text="全选/反选",
            variable=self.select_all_var,
            font=("Microsoft YaHei", 10),
            bg=bg_color,
            fg=text_color,
            activebackground=bg_color,
            activeforeground=text_color,
            selectcolor=bg_color,
            command=self.toggle_select_all
        )
        select_all_cb.pack(side="left", padx=(0, 10))
        # 右侧按钮区域
        right_button_frame = tk.Frame(bottom_frame, bg=bg_color)
        right_button_frame.pack(side="right")
        # 退出按钮
        exit_btn = ttk.Button(
            right_button_frame,
            text="退出安装",
            command=self.root.quit,
            style="Exit.TButton"
        )
        exit_btn.pack(side="left", padx=5)
        # 开始安装按钮
        install_btn = ttk.Button(
            right_button_frame,
            text="开始安装",
            command=self.start_installation,
            style="Install.TButton"
        )
        install_btn.pack(side="left", padx=5)
    def on_tree_click(self, event):
        """处理复选框点击事件"""
        region = self.tree.identify("region", event.x, event.y)
        if region == "cell":
            column = self.tree.identify_column(event.x)
            if column == "#1":  # 复选框列
                item = self.tree.identify_row(event.y)
                current_values = self.tree.item(item, 'values')
                new_state = "☑" if current_values[0] == "☐" else "☐"
                self.tree.item(item, values=(new_state, *current_values[1:]))
                self.update_select_all_state()
    def update_select_all_state(self):
        """更新全选复选框状态"""
        all_selected = all(
            self.tree.item(item, 'values')[0] == "☑"
            for item in self.tree.get_children()
        )
        self.select_all_var.set(all_selected)
    def load_software_list(self):
        """加载软件列表"""
        config = configparser.ConfigParser()
        try:
            if os.path.exists('config.ini'):
                config.read('config.ini', encoding='utf-8')
                if not os.path.exists(self.data_dir):
                    os.makedirs(self.data_dir)
                software_section = None
                if '软件列表' in config:
                    software_section = config['软件列表']
                elif 'Software' in config:
                    software_section = config['Software']
                if software_section:
                    for idx, (name, cmd) in enumerate(software_section.items(), 1):
                        if name.startswith('#'):
                            continue
                        exe_name = cmd.split()[0]
                        exe_path = os.path.join(self.data_dir, exe_name)
                        software = {
                            'name': name,
                            'exe': exe_name,
                            'path': exe_path,
                            'cmd': cmd.replace(exe_name, exe_path),
                            'size': '未知'
                        }
                        if os.path.exists(exe_path):
                            try:
                                software['size'] = self.format_size(os.path.getsize(exe_path))
                            except Exception as e:
                                print(f"获取 {name} 大小失败: {e}")
                        else:
                            print(f"文件不存在: {exe_path}")
                        self.software_list.append(software)
                        self.install_commands[name] = software['cmd']
                else:
                    messagebox.showerror("错误", "配置文件中缺少[软件列表]或[Software]段")
        except Exception as e:
            messagebox.showerror("错误", f"读取配置文件失败: {e}")
    def format_size(self, size):
        """格式化文件大小"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size  0:
            self.root.after(0, lambda: self.status_label.config(text=f"已完成 {success_count}/{total} 个软件安装"))
    def check_installation_status(self):
        """检查安装状态"""
        if self.installation_complete and all(not self.is_process_running(p[1].pid) for p in self.installation_processes):
            if self.progress_window:
                self.progress_window.destroy()
            if self.failed_installations:
                failed_list = "\n".join(self.failed_installations)
                messagebox.showwarning(
                    "安装完成",
                    f"安装完成,但有 {len(self.failed_installations)} 个软件安装失败:\n{failed_list}"
                )
            else:
                messagebox.showinfo("完成", "所有软件安装已完成")
            # 重新启用按钮
            for widget in self.root.winfo_children():
                if isinstance(widget, tk.Button):
                    widget.config(state="normal")
        else:
            self.root.after(1000, self.check_installation_status)
    def is_process_running(self, pid):
        """检查进程是否在运行"""
        try:
            return psutil.pid_exists(pid)
        except:
            return False
def main():
    root = tk.Tk()
    app = SoftwareInstaller(root)
    root.mainloop()
if __name__ == "__main__":
    main()
Leo6064   
感谢楼主分享,先存到我的云盘里备用。
Leo6064   
谢谢
419545168   
这些软件很难到吗?
Leo6064   

绿光科技 发表于 2025-6-6 19:44
这些软件很难到吗?

没听懂,什么意思?
419545168   
多谢分享!!!
Leo6064   
感谢分享!!!
419545168   
可以试试 感谢分享 !
Leo6064   
集成安装软件好
您需要登录后才可以回帖 登录 | 立即注册

返回顶部