# Is a loading window possible?

**URL:** <https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266>\
**Category:** Ignition\
**Tags:** ignition79\
**Created:** [December 6, 2018, 6:50pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266 "2018-12-06T18:50:48Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 6, 2018, 6:50pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/1 "2018-12-06T18:50:48Z")

</div>

In our program we have a section where you can edit employees in our databse, and it affects a lof of information in our db. It runs through through the table in the window, making a lot of queries per employee. I timed it at about 4 minutes.

Is there way to make it so I can get a loading screen? I tried system.gui.warningBox and placed it before the table loop, but that appears after the loop was done. I tried system.gui.messageBox, and that appeared first but then I had to click ok for the code to continue and then I’m at the same spot, the program just looks frozen and the user has no indication it’s working. Is it possible to just get a box to appear for the duration of the queries and then disappear, to load a graphic or anything really just to indicate that the program is working so the user doesn’t turn it off in the middle.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 6, 2018, 6:55pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/2 "2018-12-06T18:55:17Z")

</div>

See the documentation for system.util.invokeAsynchronous and system.util.invokeLater. The heavy lifting can be run in the background (asynchronous), and can send progress to suitable graphics via invokeLater. And there’s various topics in the archives about these functions.

---

<div class="post-metadata">

**Author:** ![Stevenson.Yuan](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Stevenson.Yuan](https://forum.inductiveautomation.com/u/Stevenson.Yuan)\
**Post date:** [December 6, 2018, 6:58pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/3 "2018-12-06T18:58:48Z")

</div>

You could do something like:

```auto
event.source.parent.getComponent("LoadingBar").visible = True
def updateUI():
	event.source.parent.getComponent("LoadingBar").visible = False

def doLotsOfStuff():
	# paste your long script here	
	system.util.invokeLater(updateUI)

system.util.invokeAsynchronous(doLotsOfStuff)

```

An extension of what @pturmel was suggesting.

You can also make it fancy if you want to post out process updates.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 6, 2018, 8:29pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/4 "2018-12-06T20:29:10Z")

</div>

I was able to get it to work going off of what you said but I had to do it slightly differently. I’ll post here in case anyone else has the same issue:

```auto
    def updateALotOfStuff(table = table, event = event):
        event.source.getComponent('Progress Bar').maximum = table.rowCount
        event.source.getComponent('Progress Bar').visible = True

        for i in range(table.rowCount):
            event.source.parent.getComponent('Progress Bar').value += 1
            # Do a lot of queries here
    
        system.nav.closeParentWindow(event)

system.util.invokeAsynchronous(updateMapRateInfo)

```

Obviously above my function I have a table and the event’s already there so they feed in fine. This was the way that worked for me. Trying to do invokeLater after the queries, the progress appeared only for a second right before the window closed anyways and wasn’t helpful. Maybe I was supposed to do it before the loop, but either way this works for me. Thanks for the help!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 6, 2018, 9:51pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/5 "2018-12-06T21:51:35Z")

</div>

You haven’t shown all of your code, but it looks like you are setting values on components from the background thread. That’s _ **very bad** _. Lock up your system kind of bad. Queries go in the background. Assigning results and updating progress has to be in the foreground, in their own invokeLater functions.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 7, 2018, 2:05pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/6 "2018-12-07T14:05:25Z")

</div>

Thanks for the warning. I was getting the progress bar to move like that but it did seem like I was misusing the async function. I now have something like this -

```auto
    def updateAlotOfStuff(tableData = tableData, event = event):
        def updateUI(tableData = tableData, event = event):
            event.source.parent.getComponent('Progress Bar').visible = True
            event.source.parent.getComponent('Progress Bar').maximum = tableData.rowCount

    system.util.invokeLater(updateUI)

    for i in range(tableData.rowCount):
        #lot of queries here
    system.nav.closeParentWindow(event)
system.util.invokeAsynchronous(updateMapRateInfo)

```

And with this I have a blank progress bar show up on screen and when the queries are done the whole thing closes which is fine. I was asked to do a progress bar, but I don’t think just having a blank one will necessarily cut it. Is there way to actually get it to the progress bar to move based on the queries without risking freezing up my system?

The only thing I could think of was to pass run the invoke later inside the for loop and also feed it the current iteration number, but that feels like I’m still just updating components from a background thread, is this safe or is that still bad practice?

My second solution, as this is not an operation we run very often, is that I’ve timed how long this query takes on average. I was going to add a solid minute to it and just throw in a timer in the invokelater function and have the progress bar load based on time, with no relation to the actual background thread. Again this has obvious problems, what if the queries are very slow today and it’s wrong and then the user goes to edit something else and its a race condition. But I am all out of ideas after that. Any suggestions?

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [December 7, 2018, 2:15pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/7 "2018-12-07T14:15:24Z")

</div>

Is it perhaps because you’ve missed the “r” on invokeLater?

```auto
     def updateAlotOfStuff(tableData = tableData, event = event):
        def updateUI(tableData = tableData, event = event):
            event.source.parent.getComponent('Progress Bar').visible = True
            event.source.parent.getComponent('Progress Bar').maximum = tableData.rowCount

    system.util.invokeLater(updateUI)

    for i in range(tableData.rowCount):
        #lot of queries here
    system.nav.closeParentWindow(event)
system.util.invokeAsynchronous(updateMapRateInfo)

```

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 7, 2018, 2:16pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/8 "2018-12-07T14:16:24Z")

</div>

Sorry I retyped my code from a VM to here not copy and pasted and made a typo, my code runs fine as is, it’s just not what I want. I’ll edit that typo though thanks.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [December 7, 2018, 2:21pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/9 "2018-12-07T14:21:06Z")

</div>

I don’t see where you’re setting the value of the progress bar. So maybe try something like this?

```auto
    def updateAlotOfStuff(tableData = tableData, event = event):
        def updateUI(tableData = tableData, event = event):
            event.source.parent.getComponent('Progress Bar').visible = True
            event.source.parent.getComponent('Progress Bar').maximum = tableData.rowCount
            event.source.parent.getComponent('Progress Bar').value = newValue

    system.util.invokeLate(updateUI)

    for i in range(tableData.rowCount):
        #lot of queries here
    system.nav.closeParentWindow(event)
system.util.invokeAsynchronous(updateMapRateInfo)

```

Obviously, newValue isn’t defined here, but you’ll need some way of calculating how much progress has been achieved, perhaps a count of row’s you’ve processed.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 7, 2018, 2:23pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/10 "2018-12-07T14:23:35Z")

</div>

That is what I want to do, but the issue is how do I get that newValue to the progress outside of just having the background thread actively updating it, which pturmel thankfully pointed out to me is a bad practice.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 7, 2018, 2:31pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/11 "2018-12-07T14:31:35Z")

</div>

Your function names and indenting don’t match up. Where’s `updateMapRateInfo` ?

The point is that you have to call updateUI multiple times from the background to keep the progress bar moving. You may need various different updateUI functions at different points to update different things in the foreground. You almost certainly need different updateUI functions to assign results to the foreground components, separate from the progress bar updates.

Consider using the helpers from [later.py](https://www.automation-pros.com/ignition/later.py), as described in [this thread](http://forum.inductiveautomation.com/t/update-gui-via-asynchronous-thread/9666), to simplify your code. Your actionPerformed event would end up something like this:

```auto
def updateMapRateInfo(ev):
	progress = ev.source.parent.getComponent("Progess Bar")
	shared.later.assignLater(progress, "indeterminate", True)
	shared.later.assignLater(progress, "visible", True)

	# Do initial queries that will let you predict the maximum
	# you should use for the progress bar. Then show it with:
	shared.later.assignLater(progress, "maximum", someMaximum)
	done = 0
	shared.later.assignLater(progress, "value", done)
	shared.later.assignLater(progress, "indeterminate", False)

	# Start doing your work, looping or whatever, with occassional
	# calls to show "done" in the the progress bar. It can be
	# every time if maximum is a small number, or every ten or
	# hundred otherwise. You don't want to spend more time
	# notifying the foreground than actually doing work.
	for row in pyds:
		done += 1
		if not (done % 10):
			shared.later.assignLater(progress, "value", done)
		# Do something with the row

	# When calculations are done, assign the results in the
	# foreground, and hide the progress bar:
	table = ev.source.parent.getComponent("Table")
	shared.later.assignLater(table, "data", newTableData)
	shared.later.assignLater(progress, "visible", False)

shared.later.callAsync(updateMapRateInfo, event)

```

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 7, 2018, 2:37pm UTC](https://forum.inductiveautomation.com/t/is-a-loading-window-possible/21266/12 "2018-12-07T14:37:12Z")

</div>

Again, a typo thats why I should copy and paste haha. Thank you for the info this is exactly what I needed.
