#!/usr/bin/python3
from PIL import Image, ImageTk
import tkinter as tk
from tkinter import ttk
from tkinter import Toplevel, messagebox
import threading
import requests
import os
import getpass
import subprocess
import zipfile
from tkinter import messagebox
import sys
from encoded_images import *
import io
import base64
import ctypes
import webbrowser
import socket
import re
ctypes.windll.user32.MessageBoxW(0, "打开帮助文档!", "提示", 0) #弹出窗口示例
def on_configure(event):
# 更新scrollregion以适应所有内容
canvas.configure(scrollregion=canvas.bbox('all'))
username = getpass.getuser()
# if getattr(sys, 'frozen', False):
# # 如果是通过PyInstaller冻结的(打包成exe)
# current_dir = os.path.dirname(sys.executable)
# else:
# # 如果是正常的python脚本运行
# current_dir = os.path.dirname(os.path.abspath(__file__))
# 创建主窗口
root = tk.Tk()
root.title(r"安装软件助手,所以软件被下载至 桌面\download_From_Self_Install 目录下")
# 设置窗口大小(可选)
root.geometry("940x690")
# 创建一个 Canvas 小部件
canvas = tk.Canvas(root)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 添加 Scrollbar 小部件并与 Canvas 关联
scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=canvas.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 配置 Canvas 使用 scrollbar
canvas.configure(yscrollcommand=scrollbar.set)
# 创建一个 Frame 放在 Canvas 上,并让所有的按钮都放在这个 Frame 中
parent_frame = tk.Frame(canvas)
# 创建一个窗口对象并添加到 Canvas 中
canvas.create_window((0, 0), window=parent_frame, anchor='nw')
# 当 Frame 的大小改变时,调整 Canvas 的 scrollregion
parent_frame.bind('<Configure>', on_configure)
child_frame = tk.Frame(parent_frame)
child_frame.pack(fill=tk.BOTH, expand=True) # 将 child_frame 填充到 parent_frame 中
def base64_to_image(image_pre):
print(image_pre)
base64_str = globals()[image_pre]
image_data = base64.b64decode(base64_str)
image = Image.open(io.BytesIO(image_data))
tk_image = ImageTk.PhotoImage(image)
return tk_image
def unzip_file(zip_file_path, extract_to):
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
# 确保覆盖已存在的文件
for member in zip_ref.namelist():
zip_ref.extract(member, path=extract_to, pwd=None)
# 下载函数 无进度条
def download_file(url, local_filename):
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
return local_filename
# 下载函数 有进度条
def download_file_jingdutiao(url, save_path):
response = requests.get(url, stream=True)
total_size = int(response.headers.get('content-length', 0))
with open(save_path, 'wb') as file:
downloaded_size = 0
for data in response.iter_content(chunk_size=1024):
if data:
file.write(data)
downloaded_size += len(data)
progress = (downloaded_size / total_size) * 100
update_progress(progress)
global close_button
if save_path.endswith(".zip"):
messagebox.showinfo("解压ZIP", "请等待程序解压ZIP,解压完在后,安装按钮自动生效")
download_dir = f"C:/Users/{username}/Desktop/download_From_Self_Install"
unzip_file(save_path, download_dir)
close_button.config(state=tk.NORMAL)
# 更新进度条和进度百分比
def update_progress(progress):
global progress_bar
global progress_label
progress_bar['value'] = progress
progress_label.config(text=f'Progress: {progress:.2f}%')
root.update_idletasks()
# 开始下载
def start_download(program_url, needed_admin, spc_url):
global download_button
download_button.config(state=tk.DISABLED)
download_dir = f"C:/Users/{username}/Desktop/download_From_Self_Install"
if not os.path.exists(download_dir):
os.makedirs(download_dir)
local_RunAsSpc_filename = f"{download_dir}" + "/" + "RunAsSpc.exe"
web_RunAsSpc_url = url_root + "/" + "RunAsSpc.exe" # 下载RunAsSpc
download_file(web_RunAsSpc_url, local_RunAsSpc_filename)
# local_RunAsSpcAdmin_filename = f"{download_dir}" + "/" + "RunAsSpcAdmin.exe"
# web_RunAsSpcAdmin_url = url_root + "/" +"RunAsSpcAdmin.exe" # 下载RunAsSpcAdmin
# download_file(web_RunAsSpcAdmin_url, local_RunAsSpcAdmin_filename)
print(spc_url)
if spc_url:
local_spc_filename = f"{download_dir}" + "/" + spc_url
web_spc_url = url_root + "/" + spc_url # 下载RunAsSpcAdmin
download_file(web_spc_url, local_spc_filename)
save_path = download_dir + "/" + program_url # 替换为实际的保存路径
url = url_root + "/" + program_url
download_thread = threading.Thread(target=download_file_jingdutiao, args=(url, save_path))
download_thread.start()
def create_new_window(needed_admin, program_url, spc_url, installation_word):
new_window = Toplevel(root)
new_window.title("下载进度示例")
new_window.geometry("300x240")
global progress_bar
# 创建进度条
progress_bar = ttk.Progressbar(new_window, orient='horizontal', length=300, mode='determinate')
progress_bar.pack(pady=20)
global progress_label
# 创建进度百分比标签
progress_label = tk.Label(new_window, text="Progress: 0.00%")
progress_label.pack(pady=10)
frame = tk.Frame(new_window)
frame.pack(pady=10)
global download_button
# 创建开始下载按钮
download_button = tk.Button(frame, text="开始下载",
command=lambda: start_download(program_url, needed_admin, spc_url))
download_button.grid(column=0, row=0, padx=10, pady=2)
# 添加一个安装按钮
def install_software():
print(needed_admin)
messagebox.showinfo("等待软件安装", f"请等待安装......")
# 指定要执行的命令及其参数 //假如
if not needed_admin: # 不是管理员
download_dir = f"C:/Users/{username}/Desktop/download_From_Self_Install"
local_program_filename = f"{download_dir}" + "/" + program_url
command = [
f"{local_program_filename}",
]
print(f"{program_url}")
print(program_url)
print(local_program_filename)
else:
download_dir = f"C:/Users/{username}/Desktop/download_From_Self_Install"
local_RunAsSpc_filename = f"{download_dir}" + "/" + "RunAsSpc.exe"
local_spc_filename = f"{download_dir}" + "/" + spc_url
command = [
f"{local_RunAsSpc_filename}",
f'/cryptfile:{local_spc_filename}', # 确保反斜杠被正确转义
'/quiet'
]
try:
# 执行命令
result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 打印标准输出和错误输出
# print("Output:", result.stdout.decode())
# print("Error:", result.stderr.decode())
print("Output:", result.stdout.decode('utf-8', errors='ignore'))
print("Output:", result.stderr.decode('utf-8', errors='ignore'))
except subprocess.CalledProcessError as e:
print(f"An error occurred while executing the command: {e}")
# print("Output:", e.stdout.decode())
# print("Error:", e.stderr.decode())
print("Output:", e.stdout.decode('utf-8', errors='ignore'))
print("Error:", e.stderr.decode('utf-8', errors='ignore'))
new_window.destroy()
global close_button
close_button = tk.Button(frame, text=f"{installation_word}", state=tk.DISABLED, command=install_software)
close_button.grid(column=1, row=0, padx=10, pady=2)
# 定义按钮点击回调函数
def button_click(button_number, needed_admin, program_url, spc_url, installation_word):
create_new_window(needed_admin, program_url, spc_url, installation_word)
# if needed_admin == False:
# print(f"按钮 is {needed_admin} !")
# else:
# print(f"按钮 is {needed_admin} !")
def get_local_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80)) #这是DNS服务器的 UDP 80端口
local_ip = s.getsockname()[0]
s.close()
return local_ip
def get_ips_by_scope(scope):
if scope == 'js_office':
# 前面是无线网段范围,见faq网站的代码 '10.54.192.', '10.54.193.', '10.54.194.', '10.54.195.','10.54.208.', '10.54.209.', '10.54.210.', '10.54.211.',
#'10.181.192.', '10.181.193.', '10.181.194.', '10.181.195.', '10.54.224.', '10.54.225.', '10.54.164.',
#后面是有线网段范围,见faq网站的代码 '10.54.70.', '10.54.71.','10.54.92.', '10.181.40.', '10.181.41.'
return {'10.54.192.', '10.54.193.', '10.54.194.', '10.54.195.','10.54.208.', '10.54.209.', '10.54.210.', '10.54.211.',
'10.181.192.', '10.181.193.', '10.181.194.', '10.181.195.','10.54.224.', '10.54.225.','10.54.164.',
'10.54.70.', '10.54.71.','10.54.92.', '10.181.40.', '10.181.41.'
}
elif scope == 'js_cpc':
# 前面是无线网段范围,见faq网站的代码 '10.54.226.', '10.54.227.'
# 后面是有线网段范围,见faq网站的代码 '10.181.206.'
return {'10.54.226.', '10.54.227.',
'10.181.206.',
'10.54.133.',
'10.181.61.'
}
elif scope == 'js_nst':
# 前面是无线网段范围,见faq网站的代码 '10.54.200.', '10.54.201.', '10.54.202.', '10.54.203.', '10.54.204.', '10.54.205.', '10.54.206.', '10.54.207.',
# 后面是有线网段范围,见faq网站的代码 '10.54.116.', '10.54.117.', '10.54.118.', '10.54.119.'
return {'10.54.200.', '10.54.201.', '10.54.202.', '10.54.203.', '10.54.204.', '10.54.205.', '10.54.206.', '10.54.207.',
'10.54.116.', '10.54.117.', '10.54.118.', '10.54.119.'
}
elif scope == 'js_mst':
# 前面是无线网段范围,见faq网站的代码 '10.54.248.', '10.54.249.', '10.54.250.', '10.54.251.',
# '10.181.208.', '10.181.209.', '10.181.210.', '10.181.211.'
# 后面是有线网段范围,见faq网站的代码 '10.54.100.', '10.54.101.', '10.54.102.', '10.54.103.', '10.54.148.', '10.54.149.', '10.54.150.', '10.54.151.',
# '10.181.48.', '10.181.49.', '10.181.50.', '10.181.51.'
return {'10.54.248.', '10.54.249.', '10.54.250.', '10.54.251.',
'10.181.208.', '10.181.209.', '10.181.210.', '10.181.211.',
'10.54.100.', '10.54.101.', '10.54.102.', '10.54.103.', '10.54.148.', '10.54.149.', '10.54.150.', '10.54.151.',
'10.181.48.', '10.181.49.', '10.181.50.', '10.181.51.'
}
elif scope == 'js_nyb':
# 前面是无线网段范围,见faq网站的代码 '10.54.236.', '10.54.237.', '10.54.238.', '10.54.239.'
# '10.54.115.'
return {'10.54.236.', '10.54.237.', '10.54.238.', '10.54.239.',
'10.54.115.'
}
elif scope == 'js_myb':
# 前面是无线网段范围,见faq网站的代码 '10.54.248.', '10.54.249.', '10.54.250.', '10.54.251.',
# '10.181.208.', '10.181.209.', '10.181.210.', '10.181.211.'
# 后面是有线网段范围,见faq网站的代码 '10.54.100.', '10.54.101.', '10.54.102.', '10.54.103.', '10.54.148.', '10.54.149.', '10.54.150.', '10.54.151.',
# '10.181.48.', '10.181.49.', '10.181.50.', '10.181.51.'
return {'10.54.244.', '10.54.245.', '10.54.246.', '10.54.247.',
'10.181.212.', '10.181.213.',
'10.54.104.', '10.54.152.',
'10.181.52.'
}
elif scope == 'jsnpi_oa':
# 有线网段范围,见faq网站的代码 '10.54.120.'
return {'10.54.120.',
}
elif scope == 'jsmp_oa':
# 有线网段范围,见faq网站的代码 '10.54.105.',
# '10.54.153.',
# '10.181.53.'
return {'10.54.105.',
'10.54.153.',
'10.181.53.'
}
return set()
def get_scope(scopes=['ALL']):
if scopes == ['ALL']:
return True
result = set()
for scope in scopes:
result = result | get_ips_by_scope(scope)
local_ip = get_local_ip()
local_ip_prefix = re.sub(r'\.\d+$', '.', local_ip)
if local_ip_prefix in result:
return True
else:
return False
list_softwares = [
{"img_url": "img/view_computer_name.png", "program_url": "get_computername.exe", "spc_url": "",
"text": "查看计算机名", "needed_admin": False, "installation_word": "查看","scope":get_scope()},
{"img_url": "img/modify_computer_name.png", "program_url": "modify_computer_name.exe",
"spc_url": "modify_computer_name.spc", "text": "修改计算机名", "needed_admin": True, "installation_word": "修改","scope":get_scope()},
{"img_url": "img/hosts.png", "program_url": "replace_hosts_zhong.exe", "spc_url": "replace_hosts_zhong.spc",
"text": "替换Hosts", "needed_admin": True, "installation_word": "替换","scope":get_scope()},
{"img_url": "img/manually_wifi.png", "program_url": "set_connect_wifi.exe", "spc_url": ".set_connect_wifi.spc",
"text": "手动连接wifi", "needed_admin": False, "installation_word": "连接","scope":get_scope()},
{"img_url": "img/bgxns.png", "program_url": "bangongxiaonenshou.exe", "spc_url": "", "text": "办公小能手",
"needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/delete_user.png", "program_url": "deleteUsers.exe", "spc_url": "deleteUsers.spc",
"text": "删除用户", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/mes.png", "program_url": "anzhuang_mes.exe", "spc_url": "", "text": "安装MES",
"needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/uninstall_chrome.png", "program_url": "uninstall_chrome.bat", "spc_url": "uninstall_chrome.spc",
"text": "卸载chrome", "needed_admin": True, "installation_word": "卸载","scope":get_scope()},
{"img_url": "img/chrome.png", "program_url": "GoogleChromev120.msi", "spc_url": "GoogleChromev120.spc",
"text": "安装chrome120", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/chrome.png", "program_url": "GoogleChrome129.0.6668.59Stablex64.msi",
"spc_url": "GoogleChrome129.0.6668.59Stablex64.spc", "text": "安装chrome129", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/firefox.png", "program_url": "Firefox-full-latest-win64.exe",
"spc_url": "Firefox-full-latest-win64.spc", "text": "安装firefox116", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/cer.png", "program_url": "start_bud_cer.zip",
"spc_url": "start_bud_cer.spc", "text": "安装bud证书", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/ip_mac.png", "program_url": "local_ip_mac.exe", "spc_url": "", "text": "查看 ip mac",
"needed_admin": False, "installation_word": "查看","scope":get_scope()},
{"img_url": "img/libreoffice.png", "program_url": "LibreOffice_7.2.7_Win_x64.msi",
"spc_url": "LibreOffice_7.2.7_Win_x64.spc", "text": "安装LibreOffice", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/py.png", "program_url": "python-3.10.6-amd64.exe", "spc_url": "python-3.10.6-amd64.spc",
"text": "安装Python", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/pycharm.png", "program_url": "pycharm-community-2022.2.1.exe",
"spc_url": "pycharm-community-2022.2.1.spc", "text": "安装Pycharm", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/test_network.png", "program_url": "test_ip_port_connection.exe", "spc_url": "",
"text": "测试网络连通", "needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/rdp_oa.png", "program_url": "OA.rdp", "spc_url": "", "text": "安装远程OA", "needed_admin": False,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/rdp_sap.png", "program_url": "SAP.rdp", "spc_url": "", "text": "安装远程SAP",
"needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/sougou_pinyin.png", "program_url": "sogou_pinyin_104a.exe", "spc_url": "sogou_pinyin_104a.spc",
"text": "安装搜狗拼音", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/sougou_wubi.png", "program_url": "sogou_wubi_31a.exe", "spc_url": "sogou_wubi_31a.spc",
"text": "安装搜狗五笔", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/ftp.png", "program_url": "FTP.exe", "spc_url": "FTP.spc", "text": "安装FTP", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/ipguard.png", "program_url": "JS-10.54.2.8-4.84-ipguard.exe",
"spc_url": "JS-10.54.2.8-4.84-ipguard.spc", "text": "安装ipguard", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/dacs.png", "program_url": "DACS_8046_last.exe", "spc_url": "DACS_8046_last.spc",
"text": "安装沙箱", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/outlook.png", "program_url": "email_re_match_compatible_count.bat", "spc_url": "",
"text": "配置邮箱(兼容版本)", "needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/outlook.png", "program_url": "xingban_email_re_match_count.exe", "spc_url": "",
"text": "配置新版邮箱", "needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/outlook2016.png", "program_url": "2016_email_re_match_count.exe", "spc_url": "",
"text": "配置2016邮箱", "needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/lx_wcdq.png", "program_url": "lixunwangzhidaquang.bat", "spc_url": "", "text": "立讯常用网址",
"needed_admin": False, "installation_word": "打开","scope":get_scope()},
{"img_url": "img/pdf.png", "program_url": "PDF.exe", "spc_url": "PDF.spc", "text": "安装PDF", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/anaconda.png", "program_url": "Anaconda3-2022.10-Windows-x86_64.exe",
"spc_url": "Anaconda3-2022.10-Windows-x86_64.spc", "text": "安装Anaconda3", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/anaconda.png", "program_url": "set_anaconda_env.exe", "spc_url": "set_anaconda_env.spc",
"text": "配置Anaconda3", "needed_admin": True, "installation_word": "配置","scope":get_scope()},
{"img_url": "img/winrar.png", "program_url": "winrar-x64-561scp.exe", "spc_url": "winrar-x64-561scp.spc",
"text": "安装WinRAR", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/seven_zip.png", "program_url": "7z2409.exe", "spc_url": "7z2409.spc",
"text": "安装7zip", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/youdao.png", "program_url": "YoudaoDictSetup.exe", "spc_url": "YoudaoDictSetup.spc",
"text": "安装有道", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/youdao.png", "program_url": "get_youdao_cidian_to_local.exe", "spc_url": "",
"text": "获取有道离线词典", "needed_admin": False, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/reset_net.png", "program_url": "reset_net.exe", "spc_url": "reset_net.spc", "text": "重置网络",
"needed_admin": True, "installation_word": "重置","scope":get_scope()},
{"img_url": "img/jianying.png", "program_url": "Jianying_pro_2_6_0_7223_jianyingpro_baidupz.exe",
"spc_url": "Jianying_pro_2_6_0_7223_jianyingpro_baidupz.spc", "text": "安装剪映", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/zysz.png", "program_url": "Touchpad-IKVD09AF_k43c_80.exe",
"spc_url": "Touchpad-IKVD09AF_k43c_80.spc", "text": "双指驱动(k43c-80)", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/office.png", "program_url": "Office2021.zip", "spc_url": "Office2021.spc", "text": "office2021",
"needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/local_sap.png", "program_url": "1.Luxshare-ICT_SAPGUI.exe", "spc_url": "1.Luxshare-ICT_SAPGUI.spc",
"text": "安装本地SAP", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/zysz2.png", "program_url": "zhaoyang_K4e_IML_touch_udated.exe",
"spc_url": "zhaoyang_K4e_IML_touch_udated.spc", "text": "K4e-IML触摸板", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/hp_audio.png", "program_url": "sp154228_hp_240_9g_yingping_drive.exe",
"spc_url": "sp154228_hp_240_9g_yingping_drive.spc", "text": "惠普240 9G音频", "needed_admin": True,
"installation_word": "安装","scope":get_scope()},
{"img_url": "img/Dell_3480.png", "program_url": "DELL3480_Audio_drive.exe", "spc_url": "DELL3480_Audio_drive.spc",
"text": "戴尔3480声卡", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/Dell_3510.png", "program_url": "Dell3510_Audio_drive.exe", "spc_url": "Dell3510_Audio_drive.spc",
"text": "戴尔3510声卡", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/hp_348_g7.png", "program_url": "HP_348_Audio_Drive.exe", "spc_url": "HP_348_Audio_Drive.spc",
"text": "惠普 348 G7声卡", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/hp_440_g8.png", "program_url": "HP_440_G8_Audio_Drive.exe", "spc_url": "HP_440_G8_Audio_Drive.spc",
"text": "惠普 440 G8声卡", "needed_admin": True, "installation_word": "安装","scope":get_scope()},
{"img_url": "img/qywx.png", "program_url": "WeCom_4.1.31.6017.exe", "spc_url": "WeCom_4.1.31.6017.spc",
"text": "企业微信", "needed_admin": True, "installation_word": "安装","scope":get_scope(['js_office','js_cpc'])}
]
# print(list_softwares)
#把 get_scope:False的移除掉
list_softwares = [software for software in list_softwares if software["scope"] is True]
# 创建并放置按钮
for i in range(len(list_softwares)):
button_number = i + 1 # 按钮编号从1开始
one_software = list_softwares[i]
needed_admin = one_software['needed_admin']
program_url = one_software['program_url']
spc_url = one_software['spc_url']
installation_word = one_software['installation_word']
# 确保替换为你的图片路径,且图片格式为PNG或GIF
# img = tk.PhotoImage(file=f"{current_dir}/{one_software['img_url']}")
img_url = one_software['img_url']
image_pre = img_url
image_pre = image_pre.split('/')[-1]
image_pre = image_pre.split('\\')[-1]
image_pre = image_pre.split('.')[0]
print(image_pre)
image = base64_to_image(image_pre)
# img = tk.PhotoImage(file=f"{one_software['img_url']}")
# 创建标签用来显示图像
label = tk.Label(child_frame, image=image)
label.image = image
# 使用 grid 布局,每行5个按钮
row = i // 8 # 计算行数
column = i % 8 # 计算列数
label.grid(row=row * 2, column=column, padx=5, pady=5)
button = tk.Button(child_frame, text=f"{one_software['text']}", command=lambda num=button_number,
needed_admin=needed_admin,
program_url=program_url,
installation_word=installation_word,
spc_url=spc_url: button_click(num,
needed_admin,
program_url,
spc_url,
installation_word,
))
button.grid(row=row * 2 + 1, column=column, padx=5, pady=5) # 添加适当的间距
##button.grid(row=i//5, column=i%5, padx=5, pady=5)
# 允许 Canvas 在 Y 轴上滚动
parent_frame.update() # 确保我们有正确的尺寸信息
canvas.configure(scrollregion=canvas.bbox("all"))
# 启动Tkinter事件循环
root.mainloop()