我对Python非常陌生(我的自学之旅已经开始了几个星期),我遇到了困难.

目标:

要让脚本读取运行该脚本的文件夹中的文件,请为找到的任何.lnk文件动态创建按钮,从目标.exe文件中提取图标并将其添加到该链接的按钮中.单击该按钮时,该按钮将启动它在创建时指向的Shortcut.lnk文件.有效地在Windows的任务栏中创建快捷方式的弹出菜单.

问题是:

我可以让它在没有图像的情况下工作,但只要我try 向tk.Button(图像)添加图像,它就只对它创建的最后一个按钮起作用.我确定这是我在获取图像的方式上做错了什么,但我就是想不出是什么.

结果:

result

上图显示了结果,前两个按钮在单击时完全不起作用,第三个按钮按预期工作.如果我注释掉将图像添加到按钮的部分,所有三个按钮都会打开各自的链接.

《守则》:

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()

我试过了:

  • 将图标另存为PNG,然后通过文件路径调用它
  • 将其添加到新对象,然后将新对象添加到tk.Button(如果链接保持不变)
  • 在添加到tk.Button之前,在内存中将其转换为PNG
  • 不是动态创建按钮(以防与重用相同的对象名称‘newButton’有关
  • 首先销毁为获取图像而调用的对象(通过类)

完全公开,我使用ChatGPT来帮助实现图标提取的代码.

推荐答案

这是因为您使用相同的变量来存储这些图像的引用,因此只有最后一个将被保留,其他的将被垃圾收集.

使用每个按钮的属性保存该按钮的图像引用:

newbutton.photo = GetImage.photo

Python相关问答推荐

Python在tuple上操作不会通过整个单词匹配

2维数组9x9,不使用numpy.数组(MutableSequence的子类)

在Polars(Python库)中将二进制转换为具有非UTF-8字符的字符串变量

Python库:可选地支持numpy类型,而不依赖于numpy

Mistral模型为不同的输入文本生成相同的嵌入

如何将一个动态分配的C数组转换为Numpy数组,并在C扩展模块中返回给Python

Pandas Loc Select 到NaN和值列表

当点击tkinter菜单而不是菜单选项时,如何执行命令?

如何在FastAPI中为我上传的json文件提供索引ID?

人口全部乱序 - Python—Matplotlib—映射

循环浏览每个客户记录,以获取他们来自的第一个/最后一个渠道

如何按row_id/row_number过滤数据帧

Beautifulsoup:遍历一个列表,从a到z,并解析数据,以便将其存储在pdf中.

如果有2个或3个,则从pandas列中删除空格

如何强制向量中的特定元素在Gekko中处于优化解决方案中

在Django中重命名我的表后,旧表中的项目不会被移动或删除

如何获取包含`try`外部堆栈的`__traceback__`属性的异常

在不中断格式的情况下在文件的特定部分插入XML标签

两个名称相同但值不同的 Select 都会产生相同的值(discord.py)

删除另一个div中的特定div容器