wxPython: How to Minimize to System Tray

I see people asking about this topic from time to time in various places on the internet. Making wxPython minimize to the tray is really quite simple, but there is at least one thing you need to watch out for. We'll get to that, but first we need to spend some time looking at some code. I actually wrote about TaskBarIcons a couple of years ago. First we'll look at the task bar icon code, which is loosely based on the aforementioned article:

import wx

########################################################################
class CustomTaskBarIcon(wx.TaskBarIcon):
    """"""
    
    #----------------------------------------------------------------------
    def __init__(self, frame):
        """Constructor"""
        wx.TaskBarIcon.__init__(self)
        self.frame = frame
        
        img = wx.Image("24x24.png", wx.BITMAP_TYPE_ANY)
        bmp = wx.BitmapFromImage(img)
        self.icon = wx.EmptyIcon()
        self.icon.CopyFromBitmap(bmp)
        
        self.SetIcon(self.icon, "Restore")
        self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.OnTaskBarLeftClick)
 
    #----------------------------------------------------------------------
    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
        """
        self.frame.Show()
        self.frame.Restore()

As you can see, we need to subclass wx.TaskBarIcon and then give it an icon. For this article, we'll be using a free icon from deviantart. Alright, so in the init, we have to jump through a couple of hoops to turn a PNG file into a format that can be used by wx's icon methods. The rest of the methods are required when sub-classing wx.TaskBarIcon. You'll note that we bind to EVT_TASKBAR_LEFT_DOWN so that when the user clicks the icon, we can restore the window.

Now we're ready to take a look at the frame's code.

import custTray
import wx

########################################################################
class MainFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Minimize to Tray")
        panel = wx.Panel(self)
        self.tbIcon = custTray.CustomTaskBarIcon(self)
        
        self.Bind(wx.EVT_ICONIZE, self.onMinimize)
        self.Bind(wx.EVT_CLOSE, self.onClose)
        
        self.Show()
        
    #----------------------------------------------------------------------
    def onClose(self, evt):
        """
        Destroy the taskbar icon and the frame
        """
        self.tbIcon.RemoveIcon()
        self.tbIcon.Destroy()
        self.Destroy()
        
    #----------------------------------------------------------------------
    def onMinimize(self, event):
        """
        When minimizing, hide the frame so it "minimizes to tray"
        """
        if self.IsIconized():
            self.Hide()
        
#----------------------------------------------------------------------
def main():
    """"""
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()
    
if __name__ == "__main__":
    main()

Here we have two event bindings. One for EVT_CLOSE and the other for EVT_ICONIZE. The latter fires when the user minimizes the frame, so we use that to minimize to the tray, which is really just hiding the frame. The other event fires when you close the frame and it's a little more important. Why? Well you need to catch the close event in case the user tries to close the app via the tray icon. And you need to make sure you remove the icon AND destroy it or your app will appear to close but actually just hang in the background.

Wrapping Up

Now you know how to minimize your wxPython application to the system tray area. I've used this for a simple email checking program before. You could use it for lots of other things, such as a monitor that responds to events by raising the frame to prominence.

Additional Reading

Copyright © 2024 Mouse Vs Python | Powered by Pythonlibrary