无忧启动论坛

标题: 程序安装管理器 [打印本页]

作者: 什么都不说吧    时间: 2025-8-14 17:00
标题: 程序安装管理器
本帖最后由 什么都不说吧 于 2025-8-15 14:11 编辑

这网上的程序安装管理器是真讨厌,配置麻烦,没办法,做个最基础功能的自己用。软件运行时会生成配置文件install_config.ini和安装程序存放文件夹data,需要把安装程序放到data文件夹里,配置文件也很简单,比如:

腾讯会议 = "腾讯会议.exe" /SilentInstall=0
qq = "qq.exe" /S
微信 = "微信.exe" /S
企业微信 = "企业微信.exe" /S

如果遇到一些软件没有自动安装参数的,那得自己想办法把软件先做成自动安装的。
软件的配色使用了论坛里另一位朋友的同类软件的配色,在此表示感谢。

程序安装管理器.part1.rar (4 MB, 下载次数: 137)     程序安装管理器.part2.rar (3.06 MB, 下载次数: 147)












作者: 小灰兔    时间: 2025-8-14 17:20
感谢分享
作者: hmaaaa    时间: 2025-8-14 17:57
感謝大大分享!^^ 辛苦了!
作者: softwarezheng1    时间: 2025-8-14 18:38
很是可以的啊
作者: AYE-阿业    时间: 2025-8-14 18:40
谢谢分享
作者: handsome_xiang    时间: 2025-8-14 18:46
感谢分享!
作者: 燕飞龙    时间: 2025-8-14 19:36

谢谢分享
作者: wn168cn@163.com    时间: 2025-8-14 19:42
挺实用 支持了
作者: rengrancunzai    时间: 2025-8-14 21:01
感谢分享
作者: 蘭蘭    时间: 2025-8-14 21:09
谢谢分享!
作者: 小龙飞    时间: 2025-8-14 21:11
感谢您的分享!
作者: jjhtya    时间: 2025-8-14 21:47
谢谢分享
作者: mokaian    时间: 2025-8-14 21:59

挺实用 支持了
作者: 呵呵#1861    时间: 2025-8-14 22:11
谢谢分享
作者: chtqq    时间: 2025-8-14 22:40
能设置安装路径吗
作者: nyren    时间: 2025-8-14 22:50
感谢楼主的分享
作者: 什么都不说吧    时间: 2025-8-15 07:16
chtqq 发表于 2025-8-14 22:40
能设置安装路径吗

默认参数,有些程序能指定安装路径的。
不过建议软件还是安装到C盘,理由如下:
1、操作系统备份后,再还原所有的软件就有了。
2、假设操作系统中了病毒,还原操作系统后C盘就干净了。如应用软件安装到其他分区,可能一开机就会有程序自动启动,这种情况下病毒可能瞬间又感染了其他程序。
作者: zhujunrang    时间: 2025-8-15 07:33
谢谢楼主分享
作者: 201012121135    时间: 2025-8-15 08:13
谢谢分享
作者: xixizhude785    时间: 2025-8-15 08:14
感谢分享
作者: 2010天月来了    时间: 2025-8-15 09:41
本帖最后由 2010天月来了 于 2025-8-15 09:49 编辑

好东西。确实好,便利部署。
你整个界面上的所有文字都可以配置文件自定义就更好了,例如右下角的立即安装等。整个程序界面的文字都可以自定义才好。

作者: jh198354    时间: 2025-8-15 10:08
谢谢分享!!!
作者: 奈绪    时间: 2025-8-15 11:30
什么都不说吧 发表于 2025-8-15 07:16
默认参数,有些程序能指定安装路径的。
不过建议软件还是安装到C盘,理由如下:
1、操作系统备份后,再 ...

大佬说的没错,备份还原更方便。
作者: 什么都不说吧    时间: 2025-8-15 13:48
piaomusic 发表于 2025-8-15 12:42
# -*- coding: utf-8 -*-
import os
import configparser

呵,这么快就反翻译出来了。。不过做程序最关键就是思路的问题,我不发源代码也没有其他意思,只是自用的程序,特别是不想涉及到版权的问题,这是原则问题。
作者: 什么都不说吧    时间: 2025-8-15 13:51
piaomusic 发表于 2025-8-15 12:42
# -*- coding: utf-8 -*-
import os
import configparser

这是我使用配色的原程序的代码,我不是抄袭你的哈,只是借用了你的配色。我的发贴中已对您表示了感谢。呵。。用deepseek写的程序,你是开源的是不?我第一个程序灵感就来自于您这里,在此再次表示感谢!
作者: 什么都不说吧    时间: 2025-8-15 13:55
piaomusic 发表于 2025-8-15 12:42
# -*- coding: utf-8 -*-
import os
import configparser

好吧,贴出源码,看下吧,真不一样。
import configparser
import subprocess
import threading
import queue
import time
import tkinter as tk
from tkinter import messagebox, Checkbutton, Button, Label, Scrollbar, Frame, ttk
import os
import sys
import ctypes
import shlex

# 获取程序所在目录
def get_app_directory():
    try:
        if getattr(sys, 'frozen', False):
            return os.path.dirname(sys.executable)
        else:
            return os.path.dirname(os.path.abspath(__file__))
    except Exception as e:
        print(f"Error getting app directory: {e}")
        return os.getcwd()  # 默认返回当前工作目录

# 创建配置文件路径
def get_config_path():
    try:
        app_dir = get_app_directory()
        return os.path.join(app_dir, "install_config.ini")
    except Exception as e:
        print(f"Error getting config path: {e}")
        return "install_config.ini"

# 获取data目录路径
def get_data_directory():
    try:
        app_dir = get_app_directory()
        return os.path.join(app_dir, "data")
    except Exception as e:
        print(f"Error getting data directory: {e}")
        return "data"

class InstallManager:
    def set_dark_theme(self, window):
        """设置改进的深色主题"""
        try:
            # 使用深色主题配色方案
            bg_color = "#2c3e50"      # 背景色
            text_color = "#ecf0f1"    # 文字颜色
            tree_bg = "#34495e"       # 表格背景
            primary_color = "#3498db" # 主色
            secondary_color = "#2ecc71" # 辅助色
            
            window.configure(bg=bg_color)
            
            # 设置默认颜色
            window.option_add("*Background", bg_color)
            window.option_add("*Foreground", text_color)
            window.option_add("*Checkbutton.Background", tree_bg)
            window.option_add("*Checkbutton.Foreground", text_color)
            window.option_add("*Label.Background", bg_color)
            window.option_add("*Label.Foreground", text_color)
            window.option_add("*Frame.Background", bg_color)
            
            # 设置滚动条颜色
            window.option_add("*Scrollbar.Background", bg_color)
            window.option_add("*Scrollbar.TroughColor", tree_bg)
            window.option_add("*Scrollbar.Slider", primary_color)
            
            # 设置进度条样式
            style = ttk.Style()
            style.theme_use('default')
            style.configure("Custom.Horizontal.TProgressbar",
                            background=primary_color,
                            troughcolor=tree_bg,
                            thickness=12,
                            lightcolor=primary_color,
                            darkcolor=bg_color,
                            bordercolor=bg_color)
        except Exception as e:
            print(f"设置深色主题时出错: {e}")

    def __init__(self, master):
        try:
            # 设置 DPI 感知以兼容高 DPI 显示器
            try:
                if hasattr(ctypes.windll, 'shcore'):
                    ctypes.windll.shcore.SetProcessDpiAwareness(1)
            except:
                pass
            
            self.master = master
            master.title("程序安装管理器")
            
            # 设置窗口大小并居中显示
            width = 600
            height = 600
            screen_width = master.winfo_screenwidth()
            screen_height = master.winfo_screenheight()
            x = (screen_width - width) // 2
            y = (screen_height - height) // 2
            master.geometry(f"{width}x{height}+{x}+{y}")
            
            # 设置深色主题
            self.set_dark_theme(master)
            
            # 安装队列和状态变量
            self.install_queue = queue.Queue()
            self.currently_installing = []
            self.max_concurrent = 1
            self.selected_count = 0
            self.installations_completed = 0
            self.total_to_install = 0
            self.current_program = ""
            self.success_count = 0  # 成功安装计数
            
            # 创建主容器框架
            self.main_frame = tk.Frame(master, bg="#2c3e50")
            self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
            
            # 创建带滚动条的容器
            self.container_frame = Frame(self.main_frame, bg="#34495e")
            self.container_frame.pack(fill=tk.BOTH, expand=True)
            
            # 创建滚动条
            self.scrollbar = Scrollbar(self.container_frame, orient=tk.VERTICAL)
            self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
            
            # 创建Canvas用于滚动
            self.canvas = tk.Canvas(
                self.container_frame,
                bg="#34495e",
                yscrollcommand=self.scrollbar.set,
                highlightthickness=0
            )
            self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
            
            # 配置滚动条
            self.scrollbar.config(command=self.canvas.yview)
            
            # 创建内部框架
            self.inner_frame = Frame(self.canvas, bg="#34495e")
            self.canvas_window = self.canvas.create_window(
                (0, 0),
                window=self.inner_frame,
                anchor="nw"
            )
            
            # 绑定事件
            self.inner_frame.bind("<Configure>", self._on_frame_configure)
            self.canvas.bind("<Configure>", self._on_canvas_configure)
            
            # 绑定鼠标滚轮事件
            self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
            self.inner_frame.bind("<MouseWheel>", self._on_mousewheel)
            self.scrollbar.bind("<MouseWheel>", self._on_mousewheel)
            
            # 加载配置
            self.programs = []
            self.check_vars = []
            self.check_buttons = []
            self.load_config()
            
            # 创建底部控制面板
            self.bottom_frame = tk.Frame(master, bg="#2c3e50")
            self.bottom_frame.pack(fill=tk.X, padx=20, pady=(0, 10), side=tk.BOTTOM)
            
            # 状态标签
            self.status_frame = tk.Frame(self.bottom_frame, bg="#2c3e50")
            self.status_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
            
            # 使用更兼容的字体
            try:
                # 尝试使用系统默认字体
                self.status_label = Label(
                    self.status_frame,
                    text="就绪",
                    fg="#2ecc71",  # 使用辅助色
                    bg="#2c3e50",
                    font=("TkDefaultFont", 11),
                    anchor="w"
                )
            except:
                # 回退到基本设置
                self.status_label = Label(
                    self.status_frame,
                    text="就绪",
                    fg="#2ecc71",  # 使用辅助色
                    bg="#2c3e50",
                    anchor="w"
                )
            self.status_label.pack(side=tk.LEFT, padx=(15, 0))
            
            # 已选安装标签
            try:
                self.selected_label = Label(
                    self.bottom_frame,
                    text="已选安装: 0",
                    fg="#3498db",  # 使用主色
                    bg="#2c3e50",
                    font=("TkDefaultFont", 12, "bold")
                )
            except:
                self.selected_label = Label(
                    self.bottom_frame,
                    text="已选安装: 0",
                    fg="#3498db",  # 使用主色
                    bg="#2c3e50"
                )
            self.selected_label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
            
            # 创建安装按钮
            try:
                self.install_btn = Button(
                    self.bottom_frame,
                    text="立即安装",
                    command=self.start_installation,
                    height=1,
                    width=10,
                    bg="#34495e",
                    fg="white",
                    activebackground="#1A2530",
                    activeforeground="white",
                    font=("TkDefaultFont", 12, "bold"),
                    relief=tk.GROOVE,
                    bd=2
                )
            except:
                self.install_btn = Button(
                    self.bottom_frame,
                    text="立即安装",
                    command=self.start_installation,
                    bg="#34495e",
                    fg="white"
                )
            self.install_btn.pack(side=tk.RIGHT, padx=(0, 15))
            
            # 创建进度显示区域
            self.progress_frame = tk.Frame(master, bg="#2c3e50", height=80)
            # 初始隐藏进度区域
            self.progress_frame.pack_forget()
            
            # 正在安装标签
            self.installing_label = Label(
                self.progress_frame,
                text="",
                fg="#3498db",  # 使用主色
                bg="#2c3e50",
                font=("TkDefaultFont", 10),
                anchor="w"
            )
            self.installing_label.pack(fill=tk.X, padx=20, pady=(5, 0))
            
            # 当前安装标签
            self.current_label = Label(
                self.progress_frame,
                text="",
                fg="#3498db",  # 使用主色
                bg="#2c3e50",
                font=("TkDefaultFont", 10),
                anchor="w"
            )
            self.current_label.pack(fill=tk.X, padx=20, pady=(0, 2))
            
            # 进度标签
            self.progress_text = Label(
                self.progress_frame,
                text="",
                fg="#2ecc71",  # 使用辅助色
                bg="#2c3e50",
                font=("TkDefaultFont", 10),
                anchor="w"
            )
            self.progress_text.pack(fill=tk.X, padx=20, pady=(0, 2))
            
            # 进度条
            self.progress_bar = ttk.Progressbar(
                self.progress_frame,
                orient="horizontal",
                length=500,
                mode="determinate",
                style="Custom.Horizontal.TProgressbar"
            )
            self.progress_bar.pack(fill=tk.X, padx=20, pady=(0, 5))
            
            # 启动安装监控线程
            self.monitor_thread = threading.Thread(target=self.monitor_installations, daemon=True)
            self.monitor_thread.start()
        
        except Exception as e:
            # 在初始化失败时显示错误信息
            error_msg = f"初始化失败: {str(e)}\n\n请检查配置文件是否存在且格式正确。"
            messagebox.showerror("致命错误", error_msg)
            self.master.destroy()
            sys.exit(1)
   
    def _on_frame_configure(self, event=None):
        """当内部框架大小改变时更新滚动区域"""
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))
   
    def _on_canvas_configure(self, event):
        """当Canvas大小改变时调整内部框架宽度"""
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_window, width=canvas_width)
   
    def _on_mousewheel(self, event):
        """处理鼠标滚轮事件"""
        # Windows使用delta值
        if event.delta > 0:
            self.canvas.yview_scroll(-1, "units")
        elif event.delta < 0:
            self.canvas.yview_scroll(1, "units")
   
    def update_status(self, message, color="#2ecc71"):  # 使用辅助色
        """更新状态标签"""
        self.status_label.config(text=message, fg=color)
   
    def update_selected_count(self):
        """更新已选安装计数"""
        self.selected_label.config(text=f"已选安装: {self.selected_count}")
   
    def load_config(self):
        """加载配置"""
        try:
            config_file = get_config_path()
            
            # 检查配置文件是否存在
            if not os.path.exists(config_file):
                # 尝试创建默认配置文件
                try:
                    self.create_default_config(config_file)
                    # 创建后重新加载
                    self.programs = []
                    self.check_vars = []
                    self.check_buttons = []
                except Exception as e:
                    error_msg = (
                        f"找不到配置文件且无法创建新文件:\n{config_file}\n"
                        f"错误: {str(e)}\n\n"
                        "请手动创建配置文件并重新启动程序。"
                    )
                    messagebox.showerror("配置错误", error_msg)
                    return
            
            config = configparser.ConfigParser()
            
            # 尝试不同编码读取配置文件
            encodings = ['utf-8', 'gbk', 'utf-8-sig', 'latin-1']
            read_ok = False
            
            for encoding in encodings:
                try:
                    config.read(config_file, encoding=encoding)
                    if 'programs' in config:
                        read_ok = True
                        break
                except Exception as e:
                    print(f"尝试 {encoding} 编码失败: {e}")
                    continue
            
            if not read_ok:
                messagebox.showerror("错误", "无法读取配置文件,请检查文件格式和编码")
                return
               
            if 'programs' not in config:
                messagebox.showerror("配置错误", f"配置文件中缺少[programs]部分\n配置文件路径: {config_file}")
                return
            
            # 创建复选框
            row = 0
            for program_name in config['programs']:
                try:
                    full_config = config['programs'][program_name].strip()
                    
                    if not full_config:
                        continue
                        
                    parts = shlex.split(full_config)
                    if not parts:
                        continue
                        
                    path = parts[0]
                    
                    args = parts[1:] if len(parts) > 1 else []
                    
                    if not os.path.isabs(path):
                        data_dir = get_data_directory()
                        path = os.path.join(data_dir, path)
                    
                    # 检查路径是否存在 - 如果不存在则跳过
                    if not os.path.exists(path):
                        print(f"警告: 找不到 {program_name} 的安装路径: {path}")
                        continue
                    
                    var = tk.BooleanVar()
                    
                    # 创建复选框
                    try:
                        cb = Checkbutton(
                            self.inner_frame,
                            text=program_name,
                            variable=var,
                            anchor="w",
                            padx=15,
                            pady=8,
                            bg="#34495e",
                            fg="white",
                            activebackground="#2c3e50",
                            activeforeground="white",
                            selectcolor="#3498db",  # 使用主色
                            font=("TkDefaultFont", 11),
                            command=lambda v=var: self.on_checkbox_change(v)
                        )
                    except:
                        # 字体回退
                        cb = Checkbutton(
                            self.inner_frame,
                            text=program_name,
                            variable=var,
                            anchor="w",
                            padx=15,
                            pady=8,
                            bg="#34495e",
                            fg="white",
                            command=lambda v=var: self.on_checkbox_change(v)
                        )
                    
                    cb.grid(row=row, column=0, sticky="ew", padx=10)
                    
                    self.programs.append({
                        'name': program_name,
                        'path': path,
                        'args': args
                    })
                    self.check_vars.append(var)
                    self.check_buttons.append(cb)
                    row += 1
                    
                except Exception as e:
                    print(f"加载程序 {program_name} 时出错: {e}")
                    continue
               
            # 如果没有加载到任何程序
            if not self.programs:
                try:
                    label = tk.Label(
                        self.inner_frame,
                        text="未找到可安装的程序,请检查配置文件",
                        bg="#34495e",
                        fg="white",
                        font=("TkDefaultFont", 12)
                    )
                    label.grid(row=0, column=0, sticky="w", padx=20, pady=20)
                except:
                    # 简单回退
                    label = tk.Label(
                        self.inner_frame,
                        text="未找到可安装的程序,请检查配置文件",
                        bg="#34495e",
                        fg="white"
                    )
                    label.grid(row=0, column=0, sticky="w", padx=20, pady=20)
               
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            error_msg = (
                f"加载配置时出错: {str(e)}\n"
                f"错误位置: 第 {exc_tb.tb_lineno} 行\n\n"
                "请检查配置文件格式是否正确。"
            )
            messagebox.showerror("配置错误", error_msg)

    def on_checkbox_change(self, var):
        """复选框状态改变时调用"""
        # 更新已选择的数量
        self.selected_count = sum(1 for v in self.check_vars if v.get())
        self.update_selected_count()
   
    def create_default_config(self, config_path):
        """创建默认配置文件"""
        default_config = """[programs]
# 格式:程序名称 = "安装程序路径" [静默安装参数]
# 示例:
# Google Chrome = "ChromeInstaller.exe" /silent
# Visual Studio Code = "VSCodeSetup.exe" /verysilent /suppressmsgboxes
# WinRAR = "wrar.exe" /S

"""
        with open(config_path, 'w', encoding='utf-8') as f:
            f.write(default_config)
            
        # 创建data目录(如果不存在)
        data_dir = get_data_directory()
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
   
    def start_installation(self):
        """开始安装选中的程序"""
        self.selected_indices = []  # 存储选中程序的索引
        for i, var in enumerate(self.check_vars):
            if var.get():
                self.selected_indices.append(i)  # 记录选中程序的索引
        
        # 使用索引获取选中的程序
        selected = [self.programs for i in self.selected_indices]
        
        if not selected:
            messagebox.showinfo("提示", "请选择至少一个程序进行安装")
            return
        
        # 隐藏"已选安装"标签
        self.selected_label.place_forget()
        
        # 禁用所有复选框
        for cb in self.check_buttons:
            cb.config(state=tk.DISABLED)
        
        # 隐藏安装按钮
        self.install_btn.pack_forget()
        
        # 清空队列并添加新任务
        while not self.install_queue.empty():
            self.install_queue.get()
        
        for program in selected:
            self.install_queue.put(program)
        
        # 重置安装计数器
        self.installations_completed = 0
        self.total_to_install = len(selected)
        self.success_count = 0  # 重置成功计数
        
        # 显示进度区域 - 放在窗口底部
        self.progress_frame.pack(fill=tk.X, padx=20, pady=(0, 0), side=tk.BOTTOM, anchor='s')
        self.update_progress(0, "准备开始安装...")
        
        # 更新正在安装标签
        self.installing_label.config(text=f"正在安装 {self.total_to_install} 个程序")
        
        # 清空状态标签(什么也不显示)
        self.status_label.config(text="")
   
    def update_progress(self, percent, message):
        """更新进度显示"""
        self.progress_bar["value"] = percent
        self.progress_text.config(text=message)
   
    def start_installation_process(self, program):
        """启动单个安装进程"""
        try:
            # 设置当前安装程序
            self.current_program = program['name']
            
            # 根据是否有静默参数显示不同的安装类型
            install_type = "静默安装" if program['args'] else "安装"
            
            # 更新当前安装标签
            self.current_label.config(text=f"当前{install_type}: {program['name']}")
            
            # 更新进度显示
            progress_percent = int((self.installations_completed / self.total_to_install) * 100)
            self.update_progress(progress_percent, f"正在{install_type} {program['name']}...")
            
            # 构建命令
            command = f'"{program["path"]}"'
            
            # 添加静默安装参数(如果有)
            if program['args']:
                command += " " + " ".join(program['args'])
            
            # 执行安装命令
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = 0  # 隐藏窗口
            
            process = subprocess.Popen(
                command,
                shell=True,
                startupinfo=startupinfo,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            
            # 添加到当前安装列表
            self.currently_installing.append(process)
            
            # 启动线程等待安装完成
            threading.Thread(target=self.wait_for_installation, args=(program, process), daemon=True).start()
            
        except Exception as e:
            self.installations_completed += 1
            # 更新进度显示为错误信息
            self.update_progress(100, f"安装失败: {program['name']}")
   
    def monitor_installations(self):
        """监控安装队列并启动安装任务"""
        while True:
            # 检查活跃安装数量
            self.currently_installing = [p for p in self.currently_installing if p.poll() is None]
            
            # 如果有空闲槽位且队列中有任务
            if len(self.currently_installing) < self.max_concurrent and not self.install_queue.empty():
                program = self.install_queue.get()
                self.start_installation_process(program)
            
            # 检查是否所有安装都已完成
            if self.install_queue.empty() and not self.currently_installing and self.total_to_install > 0:
                if self.installations_completed >= self.total_to_install:
                    self.master.after(100, self.finalize_installation)
            
            # 更新进度条
            if self.total_to_install > 0:
                progress_percent = int((self.installations_completed / self.total_to_install) * 100)
                self.master.after(100, lambda: self.update_progress(progress_percent,
                    f"已完成 {self.installations_completed}/{self.total_to_install} 个程序"))
            
            time.sleep(0.5)  # 更频繁地检查(500毫秒)
   
    def wait_for_installation(self, program, process):
        """等待安装完成并处理结果"""
        try:
            # 等待进程结束
            return_code = process.wait()
            
            # 更新安装计数
            self.installations_completed += 1
            
            # 从活跃列表中移除
            if process in self.currently_installing:
                self.currently_installing.remove(process)
            
            # 记录成功安装
            if return_code == 0:
                self.success_count += 1
            
        except Exception as e:
            self.installations_completed += 1
            if process in self.currently_installing:
                self.currently_installing.remove(process)
   
    def finalize_installation(self):
        """所有安装完成后调用"""
        # 更新进度显示
        success_message = f"成功安装 {self.success_count} 个软件"
        self.update_progress(100, success_message)
        
        # 2秒后重置界面
        self.master.after(2000, self.reset_interface)
   
    def reset_interface(self):
        """重置界面状态"""
        # 取消选中所有已安装程序的复选框
        for index in self.selected_indices:
            self.check_vars[index].set(False)
        
        # 更新已选安装计数
        self.selected_count = 0
        self.update_selected_count()
        
        # 重新显示"已选安装"标签
        self.selected_label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
        
        # 启用所有复选框
        for cb in self.check_buttons:
            cb.config(state=tk.NORMAL)
        
        # 重新显示安装按钮
        self.install_btn.pack(side=tk.RIGHT, padx=(0, 15))
        
        # 重置进度显示
        self.progress_frame.pack_forget()
        self.progress_bar["value"] = 0
        self.progress_text.config(text="")
        self.current_label.config(text="")
        self.installing_label.config(text="")  # 清空正在安装标签
        self.current_program = ""
        
        # 重置计数器
        self.total_to_install = 0
        self.installations_completed = 0
        self.success_count = 0
        
        # 恢复状态标签为"就绪"
        self.update_status("就绪", "#2ecc71")  # 使用辅助色

if __name__ == "__main__":
    try:
        root = tk.Tk()
        app = InstallManager(root)
        root.mainloop()
    except Exception as e:
        # 捕获并显示未处理的异常
        error_msg = f"程序崩溃: {str(e)}\n\n请检查配置文件是否存在且格式正确。"
        messagebox.showerror("致命错误", error_msg)
        sys.exit(1)

作者: fegr    时间: 2025-8-15 13:57
感谢楼主分享
作者: piaomusic    时间: 2025-8-15 13:58
什么都不说吧 发表于 2025-8-15 13:48
呵,这么快就反翻译出来了。。不过做程序最关键就是思路的问题,我不发源代码也没有其他意思,只是自用的 ...

我没有反翻译你的啊。 只是看的你发了。修改完善了一下原来的代码、。
作者: 什么都不说吧    时间: 2025-8-15 14:02
piaomusic 发表于 2025-8-15 12:42
[软件列表]
# 格式:软件名称 = 安装程序 参数 | 默认选中(1/0)
# 示例:

我试了好些颜色,都觉得没有你这种 颜色舒服。要么太亮,要么太暗。最终还是用了你的代码里的颜色。

作者: piaomusic    时间: 2025-8-15 14:04
本帖最后由 piaomusic 于 2025-8-15 14:08 编辑
什么都不说吧 发表于 2025-8-15 13:51
这是我使用配色的原程序的代码,我不是抄袭你的哈,只是借用了你的配色。我的发贴中已对您表示了感谢。呵 ...

不存在抄袭的说法。本来就是开源的。 我既然公开了源代码。任何人都可以随便修改。

我只是建议啊。。。 你能不能编辑一下帖子。去掉 帖子里的【链接,版权】什么的,
这些内容源代码里面都是可以修改编辑的。有什么问题?

作者: 什么都不说吧    时间: 2025-8-15 14:08
piaomusic 发表于 2025-8-15 13:58
我没有反翻译你的啊。 只是看的你发了。修改完善了一下原来的代码、。

好的,为了论坛和广大的网友,大家都多多奉献。
作者: 什么都不说吧    时间: 2025-8-15 14:10
piaomusic 发表于 2025-8-15 14:04
不存在抄袭的说法。本来就是开源的。 我既然公开了源代码。任何人都可以随便修改。

我只是建议啊。。 ...

我不是针对您,主要是这么多年一直在找同类软件,没一个自己觉得舒服点的。我马上去掉。。
作者: cnpsx    时间: 2025-8-15 14:29
piaomusic 发表于 2025-8-15 12:42
[软件列表]
# 格式:软件名称 = 安装程序 参数 | 默认选中(1/0)
# 示例:

附件无法读取的,可以弄个网盘吗? 大神
作者: mdhdehao    时间: 2025-8-15 14:45
谢谢分享
作者: 2010天月来了    时间: 2025-8-15 15:09
体验了一下,勾起多个,安装的时候要一个一个等待,现在的高性能电脑,不太想等待,指望一个点击,一大堆都开始走起。

界面的所有文字字符都支持配置文件设置就更好了。
作者: 什么都不说吧    时间: 2025-8-15 15:17
2010天月来了 发表于 2025-8-15 15:09
体验了一下,勾起多个,安装的时候要一个一个等待,现在的高性能电脑,不太想等待,指望一个点击,一大堆都 ...

这是实际情况的问题,象我公司的电脑,有些还是vdi,就是远程电脑,那性能是低得无话可说,所以我最终是没有利用多线程进行安装。就拷贝来讲,实际多个拷贝任务,并不比一个一个任务运行效率高。所以本人认为多线程安装软件并不比一个一个安装快多少。当然您说的对,现在电脑性能很好,对高性能电脑来讲,多线程安装可能是比一个一个安装快,但一个一个安装也不会慢多少的。将就了吧兄弟。我这是发的自用软件,我只能根据自己的实际情况来进行定制。见谅!
作者: fengg    时间: 2025-8-15 18:01
感谢分享
作者: luxsys88    时间: 2025-8-17 11:24
长参数不会显示出来。如这行:360ChromeX=360ChromeX-22.3.3170.64-Modified-Lite.exe /ai /gm2 /InstallPath="%ProgramFiles%"
作者: 什么都不说吧    时间: 2025-8-17 15:50
luxsys88 发表于 2025-8-17 11:24
长参数不会显示出来。如这行:360ChromeX=360ChromeX-22.3.3170.64-Modified-Lite.exe /ai /gm2 /InstallPa ...

试下这样:360ChromeX = “360ChromeX-22.3.3170.64-Modified-Lite.exe“ /ai /gm2 /InstallPath="%ProgramFiles%
作者: 什么都不说吧    时间: 2025-8-17 15:50
luxsys88 发表于 2025-8-17 11:24
长参数不会显示出来。如这行:360ChromeX=360ChromeX-22.3.3170.64-Modified-Lite.exe /ai /gm2 /InstallPa ...

也可以试下把exe改短一点。
作者: luxsys88    时间: 2025-8-17 18:01
什么都不说吧 发表于 2025-8-17 15:50
也可以试下把exe改短一点。

不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打饱包的,加上变量%ProgramFiles%参数是指定安排目录,
作者: 什么都不说吧    时间: 2025-8-17 18:44
luxsys88 发表于 2025-8-17 18:01
不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打 ...

我来测试一下。
作者: 什么都不说吧    时间: 2025-8-17 19:46
luxsys88 发表于 2025-8-17 18:01
不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打 ...

经检查,360软件的安装参数带“”号导致程序无法正确解析参数,现下在修正中。
作者: 什么都不说吧    时间: 2025-8-17 20:23
luxsys88 发表于 2025-8-17 18:01
不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打 ...

"360.exe" /ai /gm2 /InstallPath="%ProgramFiles%"  ,兄弟你这参数有问题,用批处理试过了,本身就不能全自动安装。我单位里我做了360浏览器的全自动安装程序的,我周一帮你查查参数。但/InstallPath="%ProgramFiles%"参数是没有问题的,我单位里的我是指定安装到C盘根目录的。这样方便设置文件夹的覆盖。
作者: 随缘5138    时间: 2025-8-17 21:18
不错 谢谢分享
作者: 什么都不说吧    时间: 2025-8-17 21:30
luxsys88 发表于 2025-8-17 18:01
不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打 ...

360浏览器极速版的正确自动安装参数是:--silent-install=3_1_1 --install-path="C:\Software"  ,这个C:\Software可换为%ProgramFiles%
作者: 什么都不说吧    时间: 2025-8-17 21:52
luxsys88 发表于 2025-8-17 18:01
不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打 ...

太难了,改不好。。就是这个%%符号导致的,水平有限,折腾几个小时了,不改了。
建议你先创建一个批处理,使用命令行--silent-install=3_1_1 --install-path="%ProgramFiles%"  ,跟360浏览器极速版一起打包成单文件,程序运行后自动运行批处理进行全自动安装。再将这个exe程序放到程序安装管理器里,不带参数运行,效果一样的,就是下次更新时麻烦一些。
作者: 什么都不说吧    时间: 2025-8-17 22:20
luxsys88 发表于 2025-8-17 18:01
不行,显示:读取配置文件失败:%'must be followed by'%'or'(,found:%ProgramFiles%";这软本来重打 ...

发现我安装的360浏览器极速版跟你这个版本可能不一样,所以参数可能不一样,但我也发现这个问题上被兄弟你带偏了。经测试我的那个360浏览器极速版使用以下参数可以正常安装:[programs]
360浏览器极速版 = 360.exe --silent-install=3_1_1 --install-path="c:\ProgramFiles"
这里有个问题了,我是直接指定的c:\ProgramFiles路径,没有使用兄弟你的变量。其实对于64位安装程序来讲,根本没有必要使用变量,反正都是安装到c:\ProgramFiles的是不?除非是32位程序安装时变量才有点意义,32位程序安装到32位系统上的路径是c:\ProgramFiles,安装到64位系统上路径是c:\ProgramFiles(x86),现在使用32位系统的很少了吧?何况就算是32位软件安装到c:\ProgramFiles目录,那也没有关系呀是不?
所以建议兄弟你把安装目录由变量改为 c:\ProgramFiles,问题就解决了。

作者: 奈绪    时间: 2025-8-19 10:07
为什么,我把.exe文件放在data里了,文件也配置了,但是打开管理器看不到
作者: 什么都不说吧    时间: 2025-8-19 10:23
奈绪 发表于 2025-8-19 10:07
为什么,我把.exe文件放在data里了,文件也配置了,但是打开管理器看不到

看到你的帖子后,我下载了软件,测试了,没有问题。
你把你的data文件夹里的内容截个图,配置文件里的内容也截个图,发上来看看呢。
作者: 奈绪    时间: 2025-8-19 14:23
什么都不说吧 发表于 2025-8-19 10:23
看到你的帖子后,我下载了软件,测试了,没有问题。
你把你的data文件夹里的内容截个图,配置文件里的内 ...

麻烦楼主看看是什么问题。

1.png (12.2 KB, 下载次数: 150)

1.png

2.png (22.67 KB, 下载次数: 143)

2.png

3.png (13.93 KB, 下载次数: 127)

3.png

作者: uouobb    时间: 2025-8-19 14:31
感谢分享
作者: 邪恶海盗    时间: 2025-8-19 14:42
我原来收藏过一个非常好用的软件安装管理器,界面类似下面这样的,自带配置文件编辑工具,可惜硬盘挂了弄丢了...


作者: 小栗子    时间: 2025-8-19 14:46
谢谢分享
作者: 什么都不说吧    时间: 2025-8-19 15:38
本帖最后由 什么都不说吧 于 2025-8-19 15:43 编辑
奈绪 发表于 2025-8-19 14:23
麻烦楼主看看是什么问题。

去掉最前面的#号。
上面是举例,加了#号,表示只是显示文字,并不是配置文件本身。比如正确的格式应该是:                 
                  企业微信 = "企业微信.exe" /S
而不是:     #企业微信 = "企业微信.exe" /S



作者: 什么都不说吧    时间: 2025-8-19 16:03
piaomusic 发表于 2025-8-19 14:50
测试一下。我的有没有问题。、main.txt是源代码。修改为main.py就可以编译了、
添加 | 1或 | 0即可控制 ...

兄弟你有意思吗?你试过不行,为啥我试就行呢?你跑别人帖子里推销你的软件,我就不多说了,你想推就推,又不挣钱。
但你说你试了我的软件也不行,这就是扯淡了,诋毁别人有意思么?










作者: 奈绪    时间: 2025-8-19 16:06
什么都不说吧 发表于 2025-8-19 15:38
去掉最前面的#号。
上面是举例,加了#号,表示只是显示文字,并不是配置文件本身。比如正确的格式应该是 ...

去掉#号,可以了,感谢楼主大佬指点。麻烦问一下,不是单文件版的安装程序,可以用吗?
作者: piaomusic    时间: 2025-8-19 16:07
什么都不说吧 发表于 2025-8-19 16:03
兄弟你有意思吗?你试过不行,为啥我试就行呢?你跑别人帖子里推销你的软件,我就不多说了,你想推就推, ...

我不是撤销了吗。  我以为只读取配置文件。没想到还检查DATA文件夹有没有exe文件存在。
作者: 什么都不说吧    时间: 2025-8-19 16:10
奈绪 发表于 2025-8-19 16:06
去掉#号,可以了,感谢楼主大佬指点。麻烦问一下,不是单文件版的安装程序,可以用吗?

呵,还真没注意到这个问题,理论上是可以使用的哈,自己试试吧。
作者: 奈绪    时间: 2025-8-19 16:19
什么都不说吧 发表于 2025-8-19 16:10
呵,还真没注意到这个问题,理论上是可以使用的哈,自己试试吧。

试了,不是单文件版的也可以,感谢楼主提点,辛苦了。
作者: 什么都不说吧    时间: 2025-8-19 16:22
piaomusic 发表于 2025-8-19 16:07
我不是撤销了吗。  我以为只读取配置文件。没想到还检查DATA文件夹有没有exe文件存在。

你的那个安装器我提点建议,建议你修改下:1、兼容win7到win11的所有操作系统  2、安装程序时使用多线程但要限制线程数,比如限制为三个线程,允许同时安装三个程序。
我这程序就是自用的,考虑到我自己的实际情况这样做的,因为在论坛里拿走不少好东西觉得有点内疚,所以发上论坛来,网友喜欢就拿去用,又挣不了一分钱,从未跟有人竞争的想法。网友喜欢哪个人的软件,选择权在网友。你觉得这样拼命推销有意义么?满足自己的虚荣心?
好了,在本贴中我不会再回你的贴,你愿意咋样就咋样。
作者: piaomusic    时间: 2025-8-19 16:28
什么都不说吧 发表于 2025-8-19 16:22
你的那个安装器我提点建议,建议你修改下:1、兼容win7到win11的所有操作系统  2、安装程序时使用多线程 ...

怪我测试不严谨。。和你说声  :抱歉、
作者: 13750047404    时间: 2025-8-20 13:34
程序安装管理器支持静默参数吗
作者: 什么都不说吧    时间: 2025-8-20 13:35
13750047404 发表于 2025-8-20 13:34
程序安装管理器支持静默参数吗

支持的,请看发贴时的说明。
作者: hu2036646    时间: 2025-8-20 15:27
感谢分享




欢迎光临 无忧启动论坛 (http://bbs.wuyou.net/) Powered by Discuz! X3.3