Progressbar not showing up

I have a progressbar set to invisible, but when it goes thru a loop is turned on and updated as each listItem of a listbox is checked. It works fine if have a msgbox each time it updates telling me its value, but when I remove that msgBox the progressbar doesn’t even show up. It just runs the loop and never appears. Here is my code:

[code]ProgressBar1.visible = true
ProgressBar1.value = 0
ProgressBar1.maximum = 100

for k = 0 to listBox1.listCount-1

ProgressBar1.value = k/listBox1.listCount*100
msgBox str(ProgressBar1.value) // works fine when this is here, but progressbar never shows up if it’s not.
ProgressBar1.refresh

// do some fancy checking here that normally takes about 15-20 seconds for 50 listbox entries

next

ProgressBar1.visible = false[/code]

Kinda crazy that it only shows up and increments properly if the msgBox is there.

This sounds to me like you are trying to update the UI within a tight loop. This will usually result in the behavior you are seeing (or not seeing, as the case may be…).

Rather than trying to update the progress bar within the loop, I suggest storing the progress value in a property. Then, add a timer to your window with a small period. Before the loop, set the timer’s mode to Timer.Mode.ModeMultiple. After the loop, set the timer’s mode to Timer.Mode.ModeOff. In the Timer’s Action event, read the progress value property’s value and set the Progress Bar’s value to that. This will allow the UI to update in the tight loop.

and don’t use REFRESH in the TIMER action… use INVALIDATE

ok i’ll give that a try. thanks.

There are two examples in the collection, selectable from the IDE, that are usefull in such a case.
Look at

      Desktop  -> UpdateUIFromThread

The problem you see and solutions for it are described in some earlier conversations of this forum.

Unless you move the loop to a thread, it will block both the timer and the progressbar.

Batting 0 here unfortunately. Tried setting up the timer as per Scott, but it didn’t seem to change anything. Also tried Timer1.Invalidate, but it said “timer has no member named invalidate”. Also tried setting it up exactly like the example UpdateUIFromThread but I get the error:
“Exception Message: A thread has attempted to manipulate a user interface element. This can only be done from the application’s main thread.”

I originally tried to set this up like I did in a project I have made in RS2011 R4.3, but that’s where it was just not showing up unless i added the msgbox.

Retrying Scott’s again now. Perhaps I missed something.

  1. Move the loop code to a thread.
  2. Have the loop update a property that has a big enough scope for a timer to read it.
  3. Start a timer and update the progressbar from the timer based on the property value.

Try the Task example in the Xojo Examples folder.

Long and the short of your problem is that Window services haven’t yet had time to make the progressbar visible, so any calls to updating it are just wasting cycles.

You can fix this with a bunch of solutions.

  1. Use a short delay timer to do your work, so that there’s a gap between the action being selected and the task starting, giving Window services a few milliseconds to make the progressbar visible. You must use Refresh here as invalidate is coalesced and won’t update until your task has finished.

  2. Use a thread, like others have suggested, so that the window can be updated while the thread is running.

  3. Use a helper application, the most complex solution, but you’ll get the best the performance and a smooth updating interface.

  4. The hackiest solution of all is to use app.doevents after calling progressbar.refresh. This will pause your work for a specified time duration and allow other things to kick in and update. Xojo warns against this function as it can lead to undesired results.

yeah i set it up exactly as the example app and even named everything the same. I got the LongRunningMethod to run and the progressbar displayed correctly, but as soon as I add my method to this i get the Exception message above. My method has to do an httpsocket and check the results. Could that have something to do with the error?

I’ll keep banging on this for a while and see what I can figure out. thanks for the help.

i reduced my method to nothing but a loop that updates the property for the timer to use…

autosearch method:

for k = 0 to listBox1.listCount-1
 progValue = k
next

and am still getting “Exception Message: A thread has attempted to manipulate a user interface element. This can only be done from the application’s main thread.”

Thread and Timer are both in the main window.

Thread1.run:

while progValue < listBox1.listCount autoSearch wend

Timer1.action:

  progressBar1.value = progValue/listBox1.listCount*100
  progressBar1.Refresh

I have no idea what that message really means.

You’re accessing the list box from a thread.

that’s not kosher i take it. my method has to take values from the listbox and analyze them.

Correct, you need to think of another way to get the values from your list box into your thread without the thread accessing the listbox (or any other GUI element to that matter).

You might want to use a short-period timer where every time the timer fires it processes the next row of the listbox. That would a) allow you to access the UI from your code, and b) yield time to the UI to redraw the progressbar. You can vary the number of rows it processes each time to “tune” the performance of it.

I guess I could load an array into the thread. I’ll keep banging on it. i’m not very smart but i’m persistent. :wink:

Likewise, I’m the same. You’ll learn thou.

so I can’t manipulate UI elements in a thread, but can i read their values? or do I need to somehow feed those into the thread via something like an App property? this could get kinda complicated.

Yes. In your thread, you work with Values which can be a Property of the Window or a Module, for example. In your Timer you can Update the ListBox and the Progressbar depending on the same Values you use in the Thread.

BTW: You can start a Timer from within a Thread, because a Timer is no UI Element.