'Windows Desktop GUI Automation using Python - Sleep vs tight loop

I am using PyAutoGUI library of Python to automate GUI. The application which I am automating opens a new window after I am done with data entry on my current window. Everything is taken care by python automation (data entry in my current window and the click required to open the window).

When the click is performed in the current window, the new window takes some time to open (which may range from 2 - 5 seconds). So there are two options that I can think of here:

  1. Sleep using time.sleep(5) (Con: 3 seconds might be wasted unnecessarily)
  2. Spin in a tight loop till the window appears on the screen. PyAutoGUI offers a locateOnScreen function which could be used to find out if the window has actually appeared on the screen. (However, this is CPU intensive and the function itself is CPU intensive and takes almost 2 seconds to return)

So it looks [1] is a better option to me. Is there some other technique that I may have missed that would be better than either of these two methods? Thanks.



Solution 1:[1]

For Windows only GUI automation pywinauto is a bit more full-featured (and pythonic). It waits some default time implicitly and allows explicit waiting (some CPU-non-intensive loop is inside: kind of 0.1 sec pause and quick check for changes, then waiting again).

PyAutoGUI locateOnScreen function uses advanced analysis of the screenshot. That is why it's so CPU intensive (but cross-platform).

pywinauto example:

from pywinauto import Application

app = Application(backend="win32").start(u'your_app.exe')
app.MainWindow.menu_select(u'File->Open')

app.OpenDialog.Edit.set_edit_text(u'some path')
app.OpenDialog.Open.click()
app.OpenDialog.wait_not('visible', timeout=10)

new_main_window = app.window(title_re='^.* - The Software$')
new_main_window.wait('ready', timeout=15)

Getting Started Guide is a good starting point for learning pywinauto core concept.

Solution 2:[2]

I think you can use pyautogui.getAllWindows(). This function returns all windows and their handles. so you can check when new window has added. See this:

windows=pyautogui.getAllWindows()
windows_count=len(windows)
while True:
    new_windows_count=pyautogui.getAllWindows()
    if len(new_windows_count)!=windows_count:
        break

Also, you can use the handle number of desired window to activate the desired window and bring it to foreground:

desired_window=pyautogui.Window(#enter window handle number)
desired_window.activate()

another way that I think is easier is pyautogui.getActiveWindowTitle(). This function returns title of active window. Maybe you can use that for break condition.

while True:
    title=pyautogui.getActiveWindowTitle()
    if title== "your desired window's title":
        break

Solution 3:[3]

I would go with option one but I would sleep for 2 seconds if that is the minimum average time required the open a window. After 2 seconds, I would check if the window has appeared and if not, then I would sleep again for 2 seconds. That would possibly save more time than sleeping for 5 seconds.

But since trying to check for the window is CPU intensive and time consuming, I think waiting for 5 seconds would be better over all.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3