Статьи

wxPython: создание значков на панели задач

Задумывались ли вы, как создать те маленькие значки состояния в системном трее Windows, которые обычно появляются в правом нижнем углу экрана? Инструментарий wxPython предоставляет довольно простой способ сделать это, и эта статья проведет вас через весь процесс.

Работа с кодом

По причинам, которые я не совсем понимаю, wx-компонент, который мы хотим, это wx.TaskBarIcon. Я предполагаю, что это называется, потому что системный трей является частью панели задач, или, возможно, они не различают панель задач и область лотка в других операционных системах. Во всяком случае, сначала вам нужен значок для использования. Вы можете получить свое изображение где угодно. В этом примере мы собираемся использовать изображение «конверта», которое я превратил в код Python с помощью удобной утилиты wxPython img2py. Когда вы запустите изображение через img2py, вы получите что-то вроде этого:

#----------------------------------------------------------------------
# This file was generated by img2py.py
#
from wx import ImageFromStream, BitmapFromImage
from wx import EmptyIcon
import cStringIO, zlib
 
 
def getData():
    return zlib.decompress(
'x\xda\x01\x86\x01y\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\
\x00\x00 \x08\x06\x00\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\
\x08d\x88\x00\x00\x01=IDATX\x85\xed\x97[\x9a\x83 \x0c\x85Ol\xf7\x1566#\xec\
\xac,\xace\x1e\xe4b \xfa\xa9\xa3\xe5\xc5<\x15$9\x7fO\xc0\x0b\xd1\xf0@\xcf\
\x18\xba\xaa\xdf\x007\x00\x80g\xfa1\xfe\xfe\x84o\x89ZkA\xc3\x83\x04\x00\x00\
\x8c\xe3x\xa1,\x01\x08p\xce\x89Y\xd1\x82\xfa\xe2y\xc2P\xc5\x1b\x00c\xcc\x05\
\x10Sg\x9ds0\xc6\xac\x030\xf3\x05\x10\x94\xc5\x99y\x1d\xe0\\\x88\xc9z\xe7l\
\x147\xea*\xf5\x18\xfe\x0fB\xf6\xbc\xfcs\xfd\x90-\xde\x07\x8eC\xc8\x9e\x17\
\xdbI]\xbdz#:\x06Q\xf7\xbc8\xb2\x1b`\x1f\xc4R\xcf\x83\xb8\xbe\x1b %\x16\x08\
\x12\xf3Z\xcfu\xe1\xdd\x0eL\x89\xde\xbf\xc0\xcc3\'lU\xb0=\xe7\xcc\x0c\xef\
\xfd\x02\x88\x8c\xa7:\x1b\x13\xbd\xf7\xd1\xca\x90\x0b\'\xb1:\x8a\xf8\xb4>A\
\x94|\xdd\x81E\x80)y~|(\x17\xd6\xa2\x15"0\x87\xe8`\xc9\xdf\x00@\xd9v\x19\xb2\
\xf0|}-<\x1f3\x9bXo\xe3\x1e(\xe2u\xcf\xea\xcd\xb4},\xf7\xc4\n@\xb1\xfd\x98\
\xd0\xdax\t\xa2y\x18\xb5q\x1e\xc8\xa6\x87\xd1\x99\xd6\xeb\xe3\xaaz\xfa0\xe9\
\xf5J\x96\x01\xc2\xe7\xfd5\x00\x00-@\xaf\xe8\xfeZ~\x03t\x07\xf8\x03\x82\xac\
\xa4VT\xfd\xcd\xa3\x00\x00\x00\x00IEND\xaeB`\x82\n\xa7\xa9\xa8' )
 
def getBitmap():
    return BitmapFromImage(getImage())
 
def getImage():
    stream = cStringIO.StringIO(getData())
    return ImageFromStream(stream)
 
def getIcon():
    icon = EmptyIcon()
    icon.CopyFromBitmap(getBitmap())
    return icon

Все данные изображения находятся в функции getData . Я собираюсь назвать этот файл «email_ico.py». Мы импортируем его в нашу основную программу и вызовем метод getIcon для получения значка, который мы хотим использовать. Давайте посмотрим на основное приложение сейчас:

import wx
from mail_ico import getIcon
 
########################################################################
class MailIcon(wx.TaskBarIcon):
    TBMENU_RESTORE = wx.NewId()
    TBMENU_CLOSE   = wx.NewId()
    TBMENU_CHANGE  = wx.NewId()
    TBMENU_REMOVE  = wx.NewId()
 
    #----------------------------------------------------------------------
    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)
        self.frame = frame
 
        # Set the image
        self.tbIcon = getIcon()
 
        self.SetIcon(self.tbIcon, "Test")
 
        # bind some events
        self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
        self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.OnTaskBarLeftClick)
 
    #----------------------------------------------------------------------
    def CreatePopupMenu(self, evt=None):
        """
        This method is called by the base class when it needs to popup
        the menu for the default EVT_RIGHT_DOWN event.  Just create
        the menu how you want it and return it from this function,
        the base class takes care of the rest.
        """
        menu = wx.Menu()
        menu.Append(self.TBMENU_RESTORE, "Open Program")
        menu.Append(self.TBMENU_CHANGE, "Show all the Items")
        menu.AppendSeparator()
        menu.Append(self.TBMENU_CLOSE,   "Exit Program")
        return menu
 
    #----------------------------------------------------------------------
    def OnTaskBarActivate(self, evt):
        """"""
        pass
 
    #----------------------------------------------------------------------
    def OnTaskBarClose(self, evt):
        """
        Destroy the taskbar icon and frame from the taskbar icon itself
        """
        self.frame.Close()
 
    #----------------------------------------------------------------------
    def OnTaskBarLeftClick(self, evt):
        """
        Create the right-click menu
        """
        menu = self.tbIcon.CreatePopupMenu()
        self.PopupMenu(menu)
        menu.Destroy()
 
########################################################################
class MyForm(wx.Frame):
 
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial", size=(500,500))
        panel = wx.Panel(self)
        self.tbIcon = MailIcon(self)
        self.Bind(wx.EVT_CLOSE, self.onClose)
 
    #----------------------------------------------------------------------
    def onClose(self, evt):
        """
        Destroy the taskbar icon and the frame
        """
        self.tbIcon.RemoveIcon()
        self.tbIcon.Destroy()
        self.Destroy()
 
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm().Show()
    app.MainLoop()

Первый класс в основном скопирован прямо из демонстрации wxPython и немного упрощен. Вы можете посмотреть там, если вам нужен более полный пример. В любом случае, мы связываем пару событий в нашем подклассе TaskBarIcon, который позволяет нам закрыть приложение и показать меню соответственно. Вы также заметите, что мы устанавливаем иконку, которую создали в __init__, просто вызывая его метод SetIcon и передавая строку для его всплывающей подсказки.

В методе close мы вызываем фрейм напрямую, чтобы закрыть его. Лучшим способом было бы использовать pubsub здесь. Если вы хотите немного остановиться и прочитать о pubsub, я тоже написал небольшой пост об этом. Остальная часть кода довольно понятна.

Теперь мы можем перейти к подклассу wx.Frame. Здесь мы просто создаем экземпляр класса TaskBarIcon, который мы создали ранее, и привязываем фрейм к EVT_CLOSE . Вы можете спросить об этом. Есть некоторые проблемы с использованием TaskBarIcon в Windows. Если я просто скажу, чтобы рамка закрывалась, она закрывается очень хорошо, но иконка остается, а Python просто висит на земле лалы. Если вы разрешаете пользователю закрываться только с помощью контекстного меню значка на панели задач, тогда вы можете просто добавить туда метод RemoveIcon и self.Destroy (), и вам будет полезно пойти (по какой-то причине RemoveIcon isn ‘ этого достаточно, чтобы избавиться от TaskBarIcon, поэтому вам также нужно сказать, чтобы он тоже сам себя уничтожил) Но если вы позволите пользователю нажимать маленькую «х» в верхнем правом углу, то вам нужно пойматьEVT_CLOSE и разберись с этим соответствующим образом. Когда вы перехватываете это событие, вы НЕ можете просто вызывать self.Close (), иначе вы окажетесь в бесконечном цикле, поэтому мы вместо этого вызываем self.Destroy () .

Завершение

Теперь вы сможете создать собственное приложение TaskBarIcon. Я настоятельно рекомендую посмотреть демонстрацию wxPython, чтобы узнать, что еще вы можете с ней сделать. Я думаю, что добавление значка может добавить немного блеска в ваше приложение, особенно если вам нужно, чтобы оно какое-то время было скрытно, а затем всплыло по команде пользователя.

Дальнейшее чтение

Источник