views:

362

answers:

1

I have a frame that exists as a start up screen for the user to make a selection before the main program starts. After the user makes a selection I need the screen to stay up as a sort of splash screen until the main program finishes loading in back.

I've done this by creating an application and starting a thread:

class App(wx.App):
    '''
    Creates the main frame and displays it
    Returns true if successful
    '''
    def OnInit(self):
        try:
            '''
            Initialization
            '''
            self.newFile = False
            self.fileName = ""

            self.splashThread = Splash.SplashThread(logging, self)
            self.splashThread.start()
            #...More to the class

which launches a frame:

class SplashThread(threading.Thread):
    def __init__(self, logger, app):
        threading.Thread.__init__(self)
        self.logger = logger
        self.app = app

    def run(self):
        frame = Frame(self.logger, self.app)
        frame.Show()

The app value is needed as it contains the callback which allows the main program to continue when the user makes their selection. The problem is that the startup screen only flashes for a millisecond then goes away, not allowing the user to make a selection and blocking the rest of start up.

Any ideas? Thanks in advance!

A: 

You don't need threads for this. The drawback is that the splash window will block while loading but that is an issue only if you want to update it's contents (animate it) or if you want to be able to drag it. An issue that can be solved by periodically calling wx.SafeYield for example.

import time
import wx


class Loader(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)
        self.btn1 = wx.Button(self, label="Option 1")
        self.btn2 = wx.Button(self, label="Option 2")
        sizer.Add(self.btn1, flag=wx.EXPAND)
        sizer.Add(self.btn2, flag=wx.EXPAND)
        self.btn1.Bind(wx.EVT_BUTTON, self.OnOption1)
        self.btn2.Bind(
            wx.EVT_BUTTON, lambda e: wx.MessageBox("There is no option 2")
        )

    def OnOption1(self, event):
        self.btn1.Hide()
        self.btn2.Hide()
        self.Sizer.Add(
            wx.StaticText(self, label="Loading Option 1..."),
            1, wx.ALL | wx.EXPAND, 15
        )
        self.Layout()
        self.Update()
        AppFrame(self).Show()

class AppFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        time.sleep(3)
        parent.Hide()

        # the top window (Loader) is hidden so the app needs to be told to exit
        # when this window is closed
        self.Bind(wx.EVT_CLOSE, lambda e: wx.GetApp().ExitMainLoop())


app = wx.PySimpleApp()
app.TopWindow = Loader()
app.TopWindow.Show()
app.MainLoop()
Toni Ruža
Perfect - I had thought of something similar to this before I tried threading but I just coudln't put all the pieces together... Thanks!
Fry