Добавить изображение в меню лотка окна

Я пишу простой лоток для Windows, используя python.

Мне удалось создать иконку в трее, меню, подменю. Я добавил, что добавляю изображение для определенного элемента лотка.

вот код, который я использовал. (Ссылка) Даже этот код не работал. Документация Windows не ясна.

def addMenuItem(self, wID, title, menu):
        path = os.path.dirname(os.path.abspath(__file__))
        path += "\print_pref.ico"
        option_icon = self.prep_menu_icon(path)
        item, extras = win32gui_struct.PackMENUITEMINFO(text=title,
                                                                hbmpItem=option_icon,
                                                                wID=wID)

        win32gui.InsertMenuItem(menu, 0, 1, item)


def prep_menu_icon(self, icon):
        # First load the icon.
        ico_x = win32api.GetSystemMetrics(win32con.SM_CXSMICON)
        ico_y = win32api.GetSystemMetrics(win32con.SM_CYSMICON)
        hicon = win32gui.LoadImage(0, icon, win32con.IMAGE_ICON, ico_x, ico_y, win32con.LR_LOADFROMFILE)

        hdcBitmap = win32gui.CreateCompatibleDC(0)
        hdcScreen = win32gui.GetDC(0)
        hbm = win32gui.CreateCompatibleBitmap(hdcScreen, ico_x, ico_y)
        hbmOld = win32gui.SelectObject(hdcBitmap, hbm)
        # Fill the background.
        brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU)
        win32gui.FillRect(hdcBitmap, (0, 0, 16, 16), brush)
        # unclear if brush needs to be feed.  Best clue I can find is:
        # "GetSysColorBrush returns a cached brush instead of allocating a new
        # one." - implies no DeleteObject
        # draw the icon
        win32gui.DrawIconEx(hdcBitmap, 0, 0, hicon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL)
        win32gui.SelectObject(hdcBitmap, hbmOld)
        win32gui.DeleteDC(hdcBitmap)
        return hbm

Может кто-то мне помочь.

Edit

self.tray = win32gui.CreatePopupMenu()
self.addMenuItem(1, "Open", self.tray)

Присоединение изображения. В маленькой коробке рядом с "Open" я хочу, чтобы изображение пришло. введите описание изображения здесь

Ответы

Ответ 1

Существуют проблемы с ручками против типов, которые могут не приводить к ошибкам.

Я получил эту работу, используя классы win32ui, такие как PyCDC и PyCBitMap вместо дескрипторов.

Попробуйте изменить prep_menu_icon на это:

def prep_menu_icon(self, icon):
    # First load the icon.
    ico_x = win32api.GetSystemMetrics(win32con.SM_CXSMICON)
    ico_y = win32api.GetSystemMetrics(win32con.SM_CYSMICON)
    hIcon = win32gui.LoadImage(0, icon, win32con.IMAGE_ICON, ico_x, ico_y, win32con.LR_LOADFROMFILE)

    hwndDC = win32gui.GetWindowDC(self.hwnd)
    dc = win32ui.CreateDCFromHandle(hwndDC)
    memDC = dc.CreateCompatibleDC()
    iconBitmap = win32ui.CreateBitmap()
    iconBitmap.CreateCompatibleBitmap(dc, ico_x, ico_y)
    oldBmp = memDC.SelectObject(iconBitmap)
    brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU)

    win32gui.FillRect(memDC.GetSafeHdc(), (0, 0, ico_x, ico_y), brush)
    win32gui.DrawIconEx(memDC.GetSafeHdc(), 0, 0, hIcon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL)

    memDC.SelectObject(oldBmp)
    memDC.DeleteDC()
    win32gui.ReleaseDC(self.hwnd, hwndDC)

    return iconBitmap.GetHandle()

И я получаю иконки пунктов меню:

Всплывающее меню с значками

Ответ 2

Я не могу получить пакет, настроенный на моем компьютере, поэтому не могу проверить это, но эта строка

option_icon = self.prep_menu_icon("\print_pref.ico")

вызывает некоторую озабоченность. Я не уверен, читаете ли вы файл, который, по вашему мнению, вы есть.

То, что \ будет указывать escape-последовательность. В Windows вам нужно удвоить эти обратные косые черты, чтобы предотвратить их экранирование как "\\print_pref.ico". Если вы пытаетесь загрузить файл в текущем каталоге, вам может и не понадобиться это, и он может просто указать имя файла - "print_pref.ico". Если вы пытаетесь найти файл в корневом каталоге диска, вам нужно указать букву диска "C:\\print_pref.ico".

Ответ 3

Измените строку кода 167 на item, extras = win32gui_struct.PackMENUITEMINFO(text=title,hbmpItem=5,wID=wID), после чего вы найдете значок закрытия. Но между MENUITEMINFO, построенным с помощью 5 и option_icon, нет никакого различия.

Несоответствие типов - единственная причина, по которой я могу сделать изображение. Тип option_icon равен hgdiObjdect, а MENUITEMINFO.hbmpItem требуется HBITMAP. Там должны быть литые.

Это странно, я не думаю, что hbmpitem - это дескриптор, его можно назначить на 5, поэтому он больше похож на индекс некоторой таблицы в kernel.if, так что тип не имеет значения.

Обсудите проблему handle:

вы можете попробовать все число, предварительно заданное в MENUITEMINFO, затем распечатать item, вы увидите, что номер просто перейдет в struct.and дескриптор - это своего рода указатель, этот номер не является адресом памяти. Так что это какой-то индекс.

prep_menu_icon представляет собой версию на языке python нормальной функции С++, которая переводит hcion в HBITMAP. в версии python отсутствует некоторый тип приведения, и он не работает. Но тогда GetHandle выполните некоторую магию.