Easily setting frame icon from exe file in wxPython


I've updated the relevant wxPython wiki page with this info, but thought i'd record it here for posterity too.

I'm currently playing around with writing a wxPython app. It's at the point where I'm starting to package it into executables to be run without needing Python installed.

Py2exe is the tool I'm using for creating a windows app (and py2app for the mac). It's possible to specify an icon for the executable you create with py2exe. However it'd be nice if this same icon would be used as the icon for frames created by that app. One could include an extra icon as a resource and load that up, but this seems counter to the whole DRY principle. Instead it'd be better to load the same icon from the executable we have created already.

Consulting the wxPython wiki showed that some enterprising souls had already had a go at doing this, but the solutions there relied on the win32api modules amongst others. My Windows machine didn't have this module installed (as it was running Python 2.5) and looking at the 2nd solution proposed I saw a way to remove this dependency (and thus decrease the size of the final exe as it would not need to include the extra dll's etc).

So here's the sample code, from the wiki, I posted:

import wx, sys

class MyFrame(wx.Frame):
    def __init__(self, parent=None):
        wx.Frame.__init__(self, parent, wx.ID_ANY)
            # set window icon
            if sys.platform == 'win32':
                # only do this on windows, so we don't
                # cause an error dialog on other platforms
                exeName = sys.executable
                icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
                self.SetIcon(icon)

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MyFrame()
    frame.Show(True)
    app.MainLoop()

Basically it uses sys.executable to find the exe we are running in and then gets wxPython to load the first icon it finds from it (which should be the icon of the executable itself). So when you run this directly from python (not packaged), you end up with the icon from the python executable, but when you run the packaged version you get the icon from the exe instead.

It includes the platform check, as otherwise the app throws up an error dialog on the mac and obviously I want this to work on both platforms (and Linux too in the future).