Can't make a "busy" cursor or progress bar

Simplest example:
App.MouseCursor=System.Cursors.wait

MakePdf 'Spends maybe five seconds in shell.execute command
MakePNG 'two seconds.
ShPreview 'Maybe a second, or less.
App.MousCursor=System.Cursors.StandardPointer

'I never see a cursor change… Why not?

What about using a ProgressWheel instead ?

Try putting YieldToNextThread call after each cursor change.

Code changed to test several ideas:
App.MouseCursor=System.Cursors.wait
ProgressWheel1.Visible=True
ProgressBar1.Visible=True
App.YieldToNextThread
MakePdf 'Spends maybe five seconds in shell.execute command
MakePNG 'two seconds.
ShPreview 'Maybe a second, or less.
ProgressBar1.Visible=False
ProgressWheel1.Visible=False
App.MousCursor=System.Cursors.StandardPointer

Result: Progress bar and wheel both pop up, but both frozen. Cursor does not change.
Progress wheel, being both non-animated and tiny, is not very noticeable and so does not adequately convey the need to wait.
The progressbar is better (can make it large enough to see even if it’s static) but would be better still if it were moving.
I’m going to look at just popping up a messagebox-like overlay that says “WAIT”.

If your progress bar isn’t moving you need to put your calculations on a thread so the interface can update and animate.

[quote=80016:@Gary Carroll]Result: Progress bar and wheel both pop up, but both frozen. Cursor does not change.
[/quote]

Something is wrong here. ProgressWheel should be rotating. Maybe this suggestion is to be considered ?

[quote]Eric Williams 10 hours ago
Try putting YieldToNextThread call after each cursor change.
[/quote]

Also, you can set the ProgressWheel width and height to 24 instead of 16 to make it bigger.

Place this event in the window and the controls to have the ProgressWheel follow the cursor :

Sub MouseMove(X As Integer, Y As Integer) ProgressWheel1.Left = Me.MouseX ProgressWheel1.Top = Me.MouseY End Sub

If you get the rotating ProgressWheel next to the cursor, that should convey the need to wait.

If all else fails, use an Indeterminate Progress Bar. If this did not move either, start to pray :wink:

It was already an indeterminate progress bar, and it does not move. Praying is a good thing!
The shell calls in the functions are synchronous, and where all the time is being spent. It appears that will freeze an indeterminate progress bar also. And I;m still confused as to why the cursor never changes…
I could put the functions in their own threads to make the bar move, and check for the shell complete before continuing to the next function (which cannot begin until the other is complete). Or, I can just pop up a static “busy” box big enough so it has to be notices. Does anyone know before I test whether there is a big performance penalty for using async? Clearly, there must be some performance hit, since stuff gets done (like moving the progress bar), but assuming there is little else going on in the system at the time is this trivial?

Also, I just noticed the idea to set the progress wheel size bigger. I tried that at first but while the “box” around progress wheel changed size, the image of the wheel itself did not. Maybe this is an artifact of running in the ide rather than compiled, or in a Linux VM?

I have tried to run a small project with a timed bash script to reproduce what you are describing.

The freeze definitely comes from the synchronous shell. Same thing for mouse cursors which do not change. Everything is on hold during the synchronous shell.

I have experimented with mode 1 and 2, it does not freeze the app.

You are right about the ProgressBar size, though : going from 16 to 24 does not change the size of the wheel. I thought it was the same as Mac OS.

The only issue about using asynchronous is to figure when the shell is complete, if you really want to tell the user it is over, or to display the result. The Shell.DataAvailable is what seems appropriate, but it is kind of involved (AddressOf and stuff) and I did not dive into it.

The only way a Thread can help you here is if you are performing a large amount of work in a loop, such as For…Next or Do…While. Otherwise, you won’t see any benefit.

Setting the shell to Mode=2 will do the trick for that part of the code. You will need to have a way to react to the Shell.Completed event that fires when the command is done, which will be your cue to continue with the next step of your process. You can capture this event by creating an instance of the Shell in your window and Add Handler… the Completed event.

OK. I could not really let it go :wink:

Using mode 1 or 2 is not quite as simple as using shell.result, but it is not a nightmare either.

  • I created a class called MyShell that has its Super set to Shell
  • Added to that class the Complete and DataAvailable events
  • The code I use is now “Dim s as MyShell” and so on instead of “Dim s as Shell”
  • Dragged a timer to the project and placed a subclass of it I called timer1on the window
  • In the code that calls shell.execute I added timer1.enable
  • Set the period of the subclassed timer1 to 500
  • Added to the action event of the timer

Sub Action() If s <> Nil Then Dim output As String = s.ReadAll If output <> "" Then msgbox output Me.Enabled = False End If End If End Sub

Now when the shell is complete and returns an echo, it is displayed in the MsgBox.

The UI is not frozen during the shell, all sorts of moving things can be displayed, the cursor can be changed, and I learned something for myself :slight_smile:

Oh, and I used a bash script that is timed to take time, convenient to simulate a heavy shell :

while sleep 5; do break done echo "Completed" exit