Welcome, guest | Sign In | My Account | Store | Cart
2

This recipe generates a dynamic icon (2 vertical, 5 segment bar graphs) in the system tray.

Python, 134 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import wx
import string

import sys

ID_ICON_TIMER = wx.NewId()

##
# The IconBar class
#
class IconBar:

    ##
    # \brief the constructor default left: red, default right: green
    #
    def __init__(self,l_off=[128,0,0],l_on=[255,0,0],r_off=[0,128,0],r_on=[0,255,0]):
        self.s_line = "\xff\xff\xff"+"\0"*45
        self.s_border = "\xff\xff\xff\0\0\0"
        self.s_point = "\0"*3
        self.sl_off = string.join(map(chr,l_off),'')*6
        self.sl_on = string.join(map(chr,l_on),'')*6
        self.sr_off = string.join(map(chr,r_off),'')*6
        self.sr_on = string.join(map(chr,r_on),'')*6

    ##
    # \brief gets a new icon with 0 <= l,r <= 5
    #
    def Get(self,l,r):
        s=""+self.s_line
        for i in range(5):
            if i<(5-l):
                sl = self.sl_off
            else:
                sl = self.sl_on

            if i<(5-r):
                sr = self.sr_off
            else:
                sr = self.sr_on

            s+=self.s_border+sl+self.s_point+sr+self.s_point
            s+=self.s_border+sl+self.s_point+sr+self.s_point
            s+=self.s_line

        image = wx.EmptyImage(16,16)
        image.SetData(s)

        bmp = image.ConvertToBitmap()
        bmp.SetMask(wx.Mask(bmp, wx.WHITE)) #sets the transparency colour to white 

        icon = wx.EmptyIcon()
        icon.CopyFromBitmap(bmp)

        return icon

##
# The TaskBarIcon class
#
class MyTaskBarIcon(wx.TaskBarIcon):

    l = 0
    r = 0

    ##
    # \brief the constructor
    #
    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)
        self.frame = frame
        self.IconBar = IconBar((127,127,0),(255,255,0),(0,127,127),(0,255,255))
        self.SetIconBar(self.l,self.r)

    ##
    # \brief sets the icon timer
    #
    def SetIconTimer(self):
        self.icon_timer = wx.Timer(self, ID_ICON_TIMER)
        wx.EVT_TIMER(self, ID_ICON_TIMER, self.BlinkIcon)
        self.icon_timer.Start(100)

    ##
    # \brief blinks the icon and updates self.l and self.r
    #
    def BlinkIcon(self, event):
        self.SetIconBar(self.l,self.r)
        self.l += 1
        if self.l > 5:
            self.l = 0
            self.r += 1
            if self.r > 5:
                self.r = 0
    ##
    # \brief sets the icon bar and a message
    #
    def SetIconBar(self,l,r):
        icon = self.IconBar.Get(l,r)
        self.SetIcon(icon, "L:%d,R:%d"%(l,r))

##
# The task bar application
#
class TaskBarApp(wx.Frame):

    ##
    # \brief the constructor
    #
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, -1, title, size = (1, 1),
            style=wx.FRAME_NO_TASKBAR|wx.NO_FULL_REPAINT_ON_RESIZE)

        self.tbicon = MyTaskBarIcon(self)
        self.tbicon.SetIconTimer()

        self.Show(True)

##
# The main application wx.App class
#
class MyApp(wx.App):
    def OnInit(self):
        frame = TaskBarApp(None, -1, ' ')
        frame.Center(wx.BOTH)
        frame.Show(False)
        return True

def main(argv=None):
    if argv is None:
        argv = sys.argv

    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    main()

Two things I found a bit of a bother:

wx.Icon doesn't expose the SetData() method, so the only way is to generate an image, then convert it to a bitmap then to an icon.

Windows insists on the icons being 16x16. If your icon is somewhat smaller than that (like mine was 15x16) you will need to pad it with a transparent colour.

The trick is to select a colour you will use for transparency, white in my case. then do image = wx.EmptyImage(16,16) image.SetData(s) bmp = image.ConvertToBitmap() bmp.SetMask(wx.Mask(bmp, wx.WHITE)) #sets the transparency colour to white icon = wx.EmptyIcon() icon.CopyFromBitmap(bmp)

The SetMask() makes the bitmap transparent where the pixels are white. Good news is, transparency is also transferred to the icon.

1 comment

randall flagg 6 years, 5 months ago  # | flag

Nice. Thank you very much for this piece of code.

Add a comment

Sign in to comment