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

Я пишу простой трей для окон, используя 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

Кто-нибудь может мне помочь.

Изменить

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

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


person Durgaprasad    schedule 16.08.2017    source источник
comment
есть шанс, что вы можете опубликовать полный пример, я пытался помочь с этим, но я даже не могу дойти до того, чтобы появилось меню, я использовал это в прошлом, поэтому у меня есть некоторый опыт работы с ним, просто немного ржавый. ..   -  person James Kent    schedule 23.08.2017
comment
Например, ссылка, которую я дал, содержит полный код.   -  person Durgaprasad    schedule 28.08.2017


Ответы (3)


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

Я получил это, используя классы 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()

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

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

person Christos Lytras    schedule 26.08.2017
comment
@obgnaw Я знаю это, потому что пишу MFC с 2000 года. Класс MFC CBitmap имеет HBITMAP, чтобы получить дескриптор, и, поскольку в python такого оператора быть не может, я просмотрел PyCBitmap для чего-то похожего, чтобы получить дескриптор, и это был PyCBitmap.GetHandle. - person Christos Lytras; 26.08.2017

Кажется, я не могу настроить пакет на своем компьютере, поэтому не могу проверить это, но эта строка

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

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

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

person Matthew    schedule 21.08.2017
comment
Я отредактировал вопрос. пробовал использовать os.path.dirname . Он идет на правильный файл .ico. Может быть, у файла .ico есть какие-то проблемы? где я могу получить образец файла значка. - person Durgaprasad; 21.08.2017
comment
@Durgaprasad Я думаю, что вы неправильно поняли мою точку зрения (и это может быть проблемой, а может и не быть). Вы не можете сделать \print_pref.ico. Python будет интерпретировать \p как некоторую управляющую последовательность. Вам нужно сделать \\print_pref.ico. Каталоги Windows не очень хороши, потому что они используют обратную косую черту в качестве разделителя пути, но это означает, что в коде есть escape-последовательность, поэтому они всегда должны быть удвоены (в качестве альтернативы вы можете сделать r"\print_pref.ico" - r означает интерпретировать это буквально без escape-последовательностей ). - person Matthew; 22.08.2017
comment
или просто используйте os.path.join() или os.path.normpath(), что также кажется более читаемым, чем dir += filename - person C8H10N4O2; 23.08.2017
comment
Часть проблемы @Matthew может заключаться в пути и именах файлов, а также в том, как он пытается избежать символа обратной косой черты, но до этого функция win gui для создания изображений пунктов меню не работает. Пример кода, который он предоставляет здесь, не работает, потому что есть некоторые проблемы со смешиванием классов и дескрипторов win32gui. - person Christos Lytras; 26.08.2017

Измените строку кода 167 на item, extras = win32gui_struct.PackMENUITEMINFO(text=title,hbmpItem=5,wID=wID), тогда вы найдете значок закрытия.

Но между MENUITEMINFO, созданными 5 и option_icon, нет никакой разницы.

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

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

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

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

prep_menu_icon — это версия обычной функции C++ для Python, которая переводит hcion в hbitmap.

В версии python отсутствует приведение типов, и она не работает. Но затем GetHandle творит чудеса.

person obgnaw    schedule 25.08.2017
comment
hbm — это дескриптор растрового изображения, созданного с помощью CreateCompatibleBitmap, а MENUITEMINFO.hbmpItem может принимать дескрипторы растрового изображения и некоторые специальные значения; проверьте структуру MENUITEMINFO чтобы увидеть эти значения. hbmpItem будет преобразовано в int(), поэтому я не думаю, что существует проблема несоответствия типов, см. PackMENUITEMINFO hbmpItem пакет структур. - person Christos Lytras; 25.08.2017
comment
Это не просто какой-то индекс, это либо HANDLE, либо предопределенная константа. Все типы дескрипторов заканчиваются 4-байтовыми указателями на некоторую ячейку памяти. Я говорю о том, что hbmpItem принимает как дескрипторы растрового изображения, так и некоторые предопределенные константы; вы можете увидеть это, если вы обратитесь к документации hbmpItem Type: HBITMAP; Дескриптор отображаемого растрового изображения, так что это не странно, потому что hbmpItem принимает даже дескрипторы. prep_menu_iconis ничего не переводит; он создает новое растровое изображение и рисует серый прямоугольник и изображение значка на этом растровом изображении; затем он возвращает дескриптор. - person Christos Lytras; 26.08.2017
comment
Спасибо за ваше терпеливое объяснение. @ChristosLytras - person obgnaw; 28.08.2017