Search code examples
pythonmultithreadingwxpython

How can I prevent gui freezing in wxpython?


[PROBLEM] If I click on a button that triggers a function then gui will freeze until the function concludes.

[CODE]

import wx
app = wx.App(redirect=False)
top = wx.Frame(None)
top.Maximize(True) # Set to maximize the application
sizer = wx.GridBagSizer()

def testFunction(event):
    import pyautogui
    import time
    pyautogui.FAILSAFE = False
    for i in range(2):
            pyautogui.hotkey('win','r')
            time.sleep (0.5)
            pyautogui.typewrite('cmd.exe')
            time.sleep (0.5)
            pyautogui.hotkey('enter')
            time.sleep (0.5)
            time.sleep (3)


addButton = wx.Button( top, -1, "Start", style=wx.BU_EXACTFIT )
sizer.Add(addButton, (6, 8), (2, 14), wx.EXPAND)
top.Bind(wx.EVT_BUTTON, testFunction, addButton)
top.Sizer = sizer
top.Sizer.Fit(top)
top.Show()
app.MainLoop()

[CURRENT] The gui freezes until the function ends.

[DESIRED] The gui should not freeze. Note: I think that is related to threads but I cannot quite grasp this concept.


Solution

  • Well, this worked for me:

    # -*- coding: utf-8 -*-
    import wx
    app = wx.App(redirect=False)
    top = wx.Frame(None)
    top.Maximize(False) # Set to maximize the application
    sizer = wx.GridBagSizer()
    
    def testFunction(event):
        import time
        for i in range(2):
            print ('win','r')
            time.sleep (0.5)
            print ('cmd.exe')
            time.sleep (0.5)
            print ('enter')
            time.sleep (0.5)
            print 'sleep'
            time.sleep (3)
            print u"Iteración %d".format(i+1)
    
    def thread_start(event):
        import threading
        th = threading.Thread(target=testFunction, args=(event,))
        th.start()
    
    
    
    addButton = wx.Button( top, -1, "Start", style=wx.BU_EXACTFIT )
    sizer.Add(addButton, (6, 8), (2, 14), wx.EXPAND)
    # top.Bind(wx.EVT_BUTTON, testFunction, addButton)
    top.Bind(wx.EVT_BUTTON, thread_start, addButton)
    top.Sizer = sizer
    top.Sizer.Fit(top)
    top.Show()
    app.MainLoop()
    

    You have a non-blicking gui. You could start with that and add input variables (like getting and identification to your thread so you can tell which thread is being called).

    I removed the py2autogui library because I don't have it installed (and isn't necessary to the example).