Introduction

AdvancedSplash is an easy way to add a splash screen to a wxPython application, but its use is not without pitfalls.

One of those is that programmers typically include a splash screen when their program takes a long time to load. This gives the user some feedback so they know that something is happening and that they shouldn't try to launch the application again.

The problem you will face, however, is that a long load time typically means a long time before the program execution gets to the App.MainLoop() command; and until the MainLoop is entered, the splash screen will not display correctly.

There are a lot of ways to tackle this problem. The simplest is probably to do as much initialization as possible in a function launched with a wx.CallLater call (wx.CallAfter doesn't seem to work from an OnInit function). Unfortunately, you may still face delays (such as long loads during imports) and the user interface will not be responsive until your initializer completes (so the user will not be able to click on the splash to dismiss it).

Resist the temptation to put your intialization in a background thread! This is valid only if no wx calls are made in the initialization. Never put any wx call (besides wx.CallAfter) in a background thread.

Another solution is to fork the program's execution. Display the splash screen in one fork and launch the application in the other.

Note: The following example has been written for Windows. There's no fork command in the Windows version of Python, so I'll be using spawnl instead. Feel free to post a Linux/Mac version of the following.

Example

The following example simulates 1.3 seconds of delay in doing all of my imports and 6 seconds of delay in loading my objects from the xrc file. These numbers were taken from an actual application.

Note how I put the splash screen code at the top of the file. This lets me get it done when only a minimal set of libraries are loaded.

splash.py:

SHOW_SPLASH = True
SPLASH_FN = "splash.gif"
SPLASH_TIME = 5000

import os
import sys
import wx

import AdvancedSplash

# Test to see if we need to show a splash screen. If the splash is enabled (and
# we're not the application fork), then show a splash screen and relaunch the
# same application except as the application fork.
if __name__ == "__main__":
    AppFN = sys.argv[0]
    if SHOW_SPLASH and (len(sys.argv) == 1) and AppFN.endswith(".exe"):
        App = wx.PySimpleApp()
        BM = wx.Bitmap(SPLASH_FN, wx.BITMAP_TYPE_GIF)
        F = AdvancedSplash.AdvancedSplash(None, bitmap=BM, timeout=SPLASH_TIME)
        os.spawnl(os.P_NOWAIT, AppFN, '"%s"' % AppFN.replace('"', r'\"')),
            "NO_SPLASH")
        App.MainLoop()
        sys.exit()

import time

# Simulate 1.3s of time spent importing libraries and source files
time.sleep(1.3)

class MyApp(wx.App):
    def OnInit(self):
        # Simulate 6s of time spent initializing wx components
        time.sleep(6)

        self.Frame = wx.Frame(None, -1, "Application Frame")
        self.Frame.Show()
        return True

if __name__ == "__main__":
    App = MyApp(0)
    App.MainLoop()

Here's a setup.py file I used to compile it to an .exe:

from distutils.core import setup
import py2exe

setup(windows=[{"script": "splash.py"}], data_files=[("", ("splash.gif",))])

SplashScreen While Loading (last edited 2008-09-25 23:09:32 by host-72-174-168-209)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.