我对 Python 非常陌生(我的自学之旅才几周),但我遇到了困难。
目标:
要让脚本读取运行脚本的文件夹中的文件,请为其找到的任何 .lnk 文件动态创建按钮,从目标 .exe 文件中提取图标并将其添加到该链接的按钮中。单击时,该按钮将启动创建时指向的快捷方式.lnk 文件。有效地在 Windows 任务栏中创建快捷方式的弹出菜单。
问题:
我可以让它在没有图像的情况下工作,但是一旦我尝试将图像添加到 tk.Button(image) ,它就只适用于它创建的最后一个按钮。我确信我获取图像的方式做错了,但我就是不知道是什么。
上图显示了结果,单击前两个按钮时绝对不会执行任何操作,第三个按钮按预期工作。如果我注释掉将图像添加到按钮的部分,所有三个按钮都可以打开各自的链接。
代码:
import tkinter as tk
import os
import pyautogui
from win32api import GetSystemMetrics
from PIL import Image, ImageTk
import win32com.client
import win32gui
import win32ui
def execlink(linkpath):
# print(linkpath)
os.startfile(linkpath)
class IconExtractor:
def __init__(self):
self.photo = None
self.root = None # Keep a reference to the Tkinter root window
self.label = None # Keep a reference to the Label widget
def extract_icon(self, exe_path, ico_path):
# Load the executable file
icon_handles, num_icons = win32gui.ExtractIconEx(exe_path, 0)
# Check if any icons were found
if icon_handles:
# Select the first icon from the list
h_icon = icon_handles[0]
# Create a device context
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
# Create a bitmap and draw the icon into it
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, 32, 32) # You may adjust the size (32x32 in this case)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0, 0), h_icon)
# Save the bitmap as an icon file
hbmp.SaveBitmapFile(hdc, ico_path)
# Release the icon resources
win32gui.DestroyIcon(h_icon)
else:
print("No icons found in the executable.")
def on_closing(self):
# This function is called when the user closes the Tkinter window
self.root.destroy()
def main(self, lnk_path, ico_path):
# Explicitly initialize the Tkinter event loop
# root = tk.Tk()
# root.withdraw() # Hide the root window
# lnk_path = r''
# ico_path = r''
# Get the target path from the .lnk file
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut(lnk_path)
target_path = shortcut.TargetPath
if os.path.exists(target_path):
# Extract the icon from the executable
self.extract_icon(target_path, ico_path)
# Check if the .ico file was generated successfully
if os.path.exists(ico_path):
# Open the ICO file using Pillow
with Image.open(ico_path) as img:
# Convert the image to a format compatible with PhotoImage
img = img.convert("RGBA")
self.photo = ImageTk.PhotoImage(img)
# # Create the main window
# self.root = tk.Toplevel(root)
#
# # Create a button to activate the .lnk file with the icon
# button = tk.Button(self.root, text="Activate", compound=tk.LEFT, image=self.photo,
# command=self.activate_lnk)
# button.pack(side=tk.LEFT)
#
# # Bind the closing event
# self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
#
# # Run the Tkinter event loop
# self.root.mainloop()
# else:
# print("Failed to generate .ico file.")
else:
print("Failed to retrieve the target path.")
class LinksMenu:
def __init__(self):
self.MainWindow = tk.Tk()
self.MainWindow.geometry("100x40+" + str(pyautogui.position()[0]) + "+100")
self.MainWindow.overrideredirect(True)
self.MainWindow.bind("<KeyPress>", self.closing)
self.btnframe = tk.Frame(self.MainWindow)
self.btnframe.configure(bg='')
self.btnframe.columnconfigure(0, weight=1)
count = 1
files = [File for File in os.listdir('.') if os.path.isfile(File)]
for File in files:
if File[-4:] == ".lnk":
GetImage.main(os.path.realpath(File),
os.path.dirname(os.path.realpath(File)) + '\\' + File[0:-4] + '.ico')
newbutton = (tk.Button
(self.btnframe,
name=File[0:-4].lower() + 'btn',
text=File[0:-4],
compound=tk.LEFT,
image=GetImage.photo,
font=('Arial', 14),
bg='DodgerBlue4',
command=lambda m=os.path.realpath(File): [execlink(m), self.close_after_choice()]))
newbutton.grid(padx=2,
pady=2,
row=count,
column=0,
sticky=tk.W+tk.E)
count += 1
self.btnframe.pack(fill='x')
self.MainWindow.geometry("300x"
+ str(count*45)
+ "+"
+ str(pyautogui.position()[0])
+ "+"
+ str(GetSystemMetrics(1)-(count*45)))
self.MainWindow.configure(bg='')
self.MainWindow.mainloop()
def closing(self, event):
if event.state == 8 and event.keysym == "Escape":
self.MainWindow.destroy()
def close_after_choice(self):
self.MainWindow.destroy()
if __name__ == "__main__":
GetImage = IconExtractor()
LinksMenu()
我已经尝试过:
完全公开,我使用 ChatGPT 来帮助完成图标提取的代码。
因为你使用了同一个变量来存储这些图像的引用,所以只有最后一张会被保留,其他的都会被垃圾收集。
使用每个按钮的属性保存该按钮的图像引用:
newbutton.photo = GetImage.photo