Search code examples
pythonmultithreadingwxpythonsleeploader

Frame Loader over a sleeping function in python


i wrote this snippet of code but i cannot get the expected behaviour, i guess i must use threading but i didn't figure out how to use it correctly :(

What i would like is the second Frame to continue to show the loading while the main frame runs a sleeping function.

Here's the code :

import threading
import time
import wx

class MainFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, None, id, "My main frame", wx.DefaultPosition, wx.Size(500, 300),style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX|wx.STAY_ON_TOP)

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.panel = wx.Panel(self,-1)
        self.panel.Fit()
        self.panel.Show()

        #This will freeze while sleeping...
        #self.loader = Loader(self,-1,title)
        #self.loader.Show()
        
        self.button = wx.Button(self.panel,-1,"Go To Sleep")
        self.Bind(wx.EVT_BUTTON, self.sleepy_func, self.button)

        self.another_button = wx.Button(self.panel,-1,"Go To Another Sleep")
        self.Bind(wx.EVT_BUTTON, self.another_sleepy_func, self.another_button)

        sizer.AddStretchSpacer(1)
        sizer.Add(self.button, 0, wx.ALIGN_CENTER)
        sizer.AddSpacer(20)
        sizer.Add(self.another_button, 0, wx.ALIGN_CENTER)
        sizer.AddStretchSpacer(1)

        self.panel.SetSizerAndFit(sizer)
        
    def sleepy_func(self,evt):
        time.sleep(10)

    def another_sleepy_func(self,evt):
        time.sleep(10)
        
class Loader(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, None, id, "Please Wait...", wx.DefaultPosition, wx.Size(500, 300),style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX|wx.STAY_ON_TOP)

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.panel = wx.Panel(self,-1)
        self.panel.Fit()
        self.panel.Show()

        self.txt = wx.StaticText(self.panel,-1,"Please Wait...")
        self.spinner = wx.ActivityIndicator(self.panel, size=(30, 30))

        sizer.AddStretchSpacer(1)
        sizer.Add(self.txt, 0, wx.ALIGN_CENTER)
        sizer.Add(self.spinner, 1, wx.ALIGN_CENTER)
        sizer.AddStretchSpacer(1)

        self.panel.SetSizerAndFit(sizer)
        self.spinner.Start()

        #usage : put in wx.Frame class, then call Show/Hide or Destroy

if __name__ == "__main__":
    app = wx.App()
    frame = MainFrame(None,-1,None)
    frame.Show(True)
    frame.Centre()
    app.MainLoop()

Thanks everyone for helping ! Never used threads before...

I didn't let my threading tests, it was too much a mess and not working !

Already tried solutions : Threading , Multiprocessing


Solution

  • I think i finally got it by myself, if someone could confirm would be great !

    Here's the i think working code

    import threading
    import time
    import wx
    
    def threaded(fn):
        def wrapper(*args, **kwargs):
            threading.Thread(target=fn, args=args, kwargs=kwargs).start()
        return wrapper
    
    class MainFrame(wx.Frame):
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, None, id, title, wx.DefaultPosition, wx.Size(500, 300),style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX|wx.STAY_ON_TOP)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            self.panel = wx.Panel(self,-1)
            self.panel.Fit()
            self.panel.Show()
    
            self.loader = Loader(self,-1,"Test loading...")       
            
            self.button = wx.Button(self.panel,-1,"Show loading")
            self.Bind(wx.EVT_BUTTON, self.show_loading, self.button)
    
            self.button2 = wx.Button(self.panel,-1,"Sleep")
            self.Bind(wx.EVT_BUTTON, self.another_sleepy_func, self.button2)
    
            sizer.AddStretchSpacer(1)
            sizer.Add(self.button, 0, wx.ALIGN_CENTER)
            sizer.AddSpacer(10)
            sizer.Add(self.button2, 0, wx.ALIGN_CENTER)
            sizer.AddStretchSpacer(1)
    
            self.panel.SetSizerAndFit(sizer) 
    
        @threaded
        def show_loading(self,evt):
            self.loader.Show()
            
        @threaded
        def another_sleepy_func(self,evt):
            print("sleeping")
            for i in range(10,0,-1):
                time.sleep(1)
                print (i)
            
    class Loader(wx.Frame):
        def __init__(self, parent, id, title):
            wx.Frame.__init__(self, None, id, title, wx.DefaultPosition, wx.Size(500, 300),style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX|wx.STAY_ON_TOP)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            self.panel = wx.Panel(self,-1)
            self.panel.Fit()
            self.panel.Show()
    
            self.txt = wx.StaticText(self.panel,-1,"Please Wait...")
            self.spinner = wx.ActivityIndicator(self.panel, size=(30, 30))
    
            sizer.AddStretchSpacer(1)
            sizer.Add(self.txt, 0, wx.ALIGN_CENTER)
            sizer.Add(self.spinner, 1, wx.ALIGN_CENTER)
            sizer.AddStretchSpacer(1)
    
            self.panel.SetSizerAndFit(sizer)
            self.spinner.Start()
    
            #usage : put in wx.Frame class, then call Show/Hide or Destroy
    
    if __name__ == "__main__":
        app = wx.App()
        frame = MainFrame(None,-1,"Main frame")
        frame.Show(True)
        frame.Centre()
        app.MainLoop()