הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Friday, June 19, 2009 3:01 PM
In VB.net, is it possible to create a pause in a while loop, wait for user input (for example, hit the STOP button, if desired), and if no input within say... a second, continue on?
Basically I have a loop that increments and continues to increment but I am unable to stop the program if desired. To stop the program, VB must:
Serial.Write("s" & Chr(13))
Where "s" is a string that the controller looks for to stop all current processes. I would like my while loop to have a chance for the user to cancel, if desired.
Thanks in advance
Matthew
All replies (24)
Monday, June 22, 2009 3:27 PM ✅Answered
When the program is running, I want the value of AzString to be converted into int32 (taken care of), incremented, converted back into string (taken care of), write Serial.write("W" & AzString & ElString & chr(13)) to move the antenna 3 degrees, then pause for 2-3 seconds. The only thing wrong is that once the incrementing starts there is no way to interrupt it using a pause button and then continue when the user desires.
If you run the referenced (above) section of code in your app, do it from a start/stop button. Clicking start would start that section of your code IN A SEPARATE THREAD. By running all of that code in a separate thread, you'll be able to use the button anytime you need to. Here is a link, which you may or may not have already seen, that might be of use to you. Look it over an see if there is any code that you could use.
http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/43b1b2ea-329d-46ac-9926-0334e8dcd1d1/
Doug
SEARCH ... then ask
Monday, June 22, 2009 4:13 PM ✅Answered
I thought there might be some more difficulty when the stream part comes in to play. However, as my code stands it does allow you to have full control of the form in-between ticks -- because it has such a short activity within its method block. It sounds to me like you need to investigate using a BackgroundWorker object -- perhaps do the reading/writing within the DoWork handler so that the form's resources are not taken up. That would probably solve all your problems. If you're not familiar with this class do a search in these forums - there are many examples of its use here.
Wednesday, June 24, 2009 12:51 PM ✅Answered | 1 vote
here is a stub on how to use a backgroundworker to do what you are trying to do, it will need some tweeking for your specific application.
Public Class Form1
Private WithEvents MyWorker As System.ComponentModel.BackgroundWorker
Private Pause As Boolean = False
Private Sub Form3_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
MyWorker.WorkerSupportsCancellation = True
End Sub
Private Sub MyWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles MyWorker.DoWork
Do
If Not Pause Then
'do your work
End If
System.Threading.Thread.Sleep(3000) ' wait 3 seconds
Loop Until MyWorker.CancellationPending
End Sub
Private Sub MyWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles MyWorker.RunWorkerCompleted
'clean up what ever you need to.
End Sub
Private Sub Start_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Start.Click
MyWorker = New System.ComponentModel.BackgroundWorker
MyWorker.RunWorkerAsync()
End Sub
Private Sub PauseContinue_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PauseContinue.Click
Me.Pause = Not Me.Pause
If Me.Pause Then
PauseContinue.Text = "Continue"
Else
PauseContinue.Text = "Pause"
End If
End Sub
Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click
MyWorker.CancelAsync()
End Sub
End Class
Adam - Please remember to mark the answers.
Friday, June 19, 2009 3:12 PM
Only when that loop is calling a method in the loop.
Then you can handle before the method is called/invoked a switch which you have set by a button.
Normally a method will always processed until the end
Private X as boolean = False
Private sub A
For x = 0 to whateverloop
B
end for
end sub
Private sub B
if XStop then
threading.thread.sleep(10000)'10 seconds
End if
'Do what you want to do
XStop = false
end sub
Private Sub Handles_Button (blabla
XStop = True
end sub
Typed in this messages so watch typos or small mistakes
Success
Cor
Friday, June 19, 2009 3:35 PM
Private XStop as Boolean = False
If Serial.IsOpen = True Then
While Azimuth <= 450
Azimuth += 3
Do B
End While
End If
Private Sub B
If XStop = true then
threading.thread.sleep(4000)
End if
If Xstop = false
ElString = Elevation.ToString.PadLeft(3, Chr(48))
AzString = Azimuth.ToString.PadLeft(3, Chr(48))
Serial.Write("W" & AzString & " " & ElString & Chr(13))
Label1.Text = AzString
System.Threading.Thread.Sleep(4000)
End If
Something similar to this? What would make Xstop true, could I assign a button click to that?
Saturday, June 20, 2009 7:57 AM
Something similar to this? What would make Xstop true, could I assign a button click to that?
That is in the code I've showed
In that code, I set also that stop again to "on", it took me more then some minutes first to understand your problem and then to get that part in it.
Success
Cor
Monday, June 22, 2009 1:15 PM
Cor, I appreciate your help but am still a little lost in how to create/invoke a method inside a loop. This is the loop that I currently have:
If Serial.IsOpen = True Then
While Elevation <= 180
Elevation += 3
ElString = Elevation.ToString.PadLeft(3, Chr(48))
AzString = Azimuth.ToString.PadLeft(3, Chr(48))
Serial.Write("W" & AzString & " " & ElString & Chr(13))
System.Threading.Thread.Sleep(2000)
Label2.Text = ElString
End While
End If
I'd like to have a button that is able to be pushed while the loop is running. If the button is pushed in, I'd like the button name to change to "Continue" and have the loop pause until the button is pushed again, which then reverts the button back to "Pause" and the loop carries on.
I am a little confused by your posts. I will continue to play around with it but if you are able to provide some more insight and have time to do so, I'd love to hear it.
Thanks for your help
Matthew
Monday, June 22, 2009 1:35 PM
Currently, its part of a timer called ElTimer:
'
'Elevation Increment
'
Private Sub ElTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ElTimer.Tick
If Serial.IsOpen = True Then
Serial.Write("C")
Serial.Write(Chr(13))
AzString = Serial.ReadLine()
End If
If Serial.IsOpen = True Then
Serial.Write("B")
Serial.Write(Chr(13))
ElString = Serial.ReadLine()
End If
Elevation = Convert.ToInt32(ElString.Substring(ElString.IndexOf("+") + 2))
Azimuth = Convert.ToInt32(AzString.Substring(AzString.IndexOf("+") + 2))
If Elevation <> Elevation Then
Exit Sub
End If
If Serial.IsOpen = True Then
While Elevation <= 180
Elevation += 3
ElString = Elevation.ToString.PadLeft(3, Chr(48))
AzString = Azimuth.ToString.PadLeft(3, Chr(48))
Serial.Write("W" & AzString & " " & ElString & Chr(13))
System.Threading.Thread.Sleep(2000)
Label2.Text = ElString
End While
End If
End Sub
And I just do a ElTimer.Start() to start the incrementing. Only thing is, once I start ElTimer, the loop will run until complete or I physically stop running the program.
Monday, June 22, 2009 2:00 PM | 1 vote
Can you try this sample, it is about your first question not the second, which is a little bit more complicated, but probably you see it when you have tried this one. It needs 2 buttons while button 2 is to stop the program, it shows a running clock and if you click on that it stops 5 minutes showing.
Public Class Form1
Private swStop As Boolean
Private Sub DisplayTime()
Button1.Text = Now.ToLongTimeString
Application.DoEvents()
If swStop Then
Threading.Thread.Sleep(5000)
End If
swStop = False
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
swStop = True
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Button2.Visible = False
Dim Juz As DateTime = Now.AddMinutes(10)
While Juz >= Now
DisplayTime()
Button1.Text = Now.ToShortTimeString
End While
End Sub
End Class
Success
Cor
Monday, June 22, 2009 2:23 PM
When button2 was pressed, button 1 became a clock.
I wanted to use something like this to make 1 button a pause/continue button. My problem is that I am unable to push the button once the "start" button is pushed because the loop continuously runs.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Button2.Text = "Pause"
Static Downstate As Long
Downstate = Not Downstate
If Not Downstate Then
Button2.Text = "Pause"
Else
Button2.Text = "Continue"
End If
End Sub
End Class
Monday, June 22, 2009 2:45 PM | 1 vote
Try the following code. I think this is what you are asking for -- the ability to pause the stream (in this case an incrementing counter)...
Public Class Form1
Private Paused As Boolean = False
Private WithEvents tim As New Timer
'REQUIRES A BUTTON (Button1) AND A LABEL (Label1) ON THE FORM.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
tim.Interval = 250
tim.Enabled = True
Button1.Text = "Pause"
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Paused = Not Paused
If Not Paused Then
Button1.Text = "Pause"
tim.Enabled = True
Else
Button1.Text = "Continue"
tim.Enabled = False
End If
End Sub
Private Sub tim_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tim.Tick
Static counter As Int32 = 0
counter += 1
Label1.Text = counter.ToString
End Sub
End Class
Monday, June 22, 2009 2:52 PM
Dig boy, that is very similar to what I currently have. The only problem is that once the incrementing loop starts, the button to "pause" the program becomes useless because the program will not allow the button to be pressed (and stops all other functions as well) until the loop stops.
To give a broader overview of what I am dealing with here: The program opens a serial connection to an antenna drive controller. The antenna drive controller moves based on a string input of:
Serial.write("W" & AzString & ElString & chr(13))
Where w is just w, AzString is a 3 digit string of "aaa" and ElString is the same with a string of "eee" where aaa is 000 to 450 and eee is 000 to 180
When the program is running, I want the value of AzString to be converted into int32 (taken care of), incremented, converted back into string (taken care of), write Serial.write("W" & AzString & ElString & chr(13)) to move the antenna 3 degrees, then pause for 2-3 seconds. The only thing wrong is that once the incrementing starts there is no way to interrupt it using a pause button and then continue when the user desires.
Thank you both for your continued help.
Monday, June 22, 2009 2:57 PM | 1 vote
When button2 was pressed, button 1 became a clock.
I wanted to use something like this to make 1 button a pause/continue button. My problem is that I am unable to push the button once the "start" button is pushed because the loop continuously runs.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Button2.Text = "Pause"
Static Downstate As Long
Downstate = Not Downstate
If Not Downstate Then
Button2.Text = "Pause"
Else
Button2.Text = "Continue"
End If
End Sub
End Class
Did you click on that clock, that stops the loop 5 seconds and then the clock goes on?
You see that DoEvents in the I gave you code, the problem is, that it eats completely your processor in a continuous loop which you want
It is in my idea better that when the stop button is stopped, you stop all movements, keep where it was and with the start button start the proces again. That is the normal approach by the way.
However, that is not what you were asking for, and I simply fullfiled the question, not the problem.
Success
Cor
Monday, June 22, 2009 3:03 PM
I would very much prefer to attack the problem and not the symptom, if possible. Could you explain this DoEvents process to me? Can that be inserted into my loop to help prevent the loop from starting and not wanting to stop?
I could implement a button that would issue a command
Serial.write("s" & chr(13)) this issues a stop command to the device. I believe ElString and AzString should retain their values as long as ElTimer and AzTimers are stopped as well.
Monday, June 22, 2009 3:07 PM | 1 vote
Hi MBorowski,
i would do it in this way:
Public Class Form1
Private bStop As Boolean
Private bEnd As Boolean
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
bStop = Not bStop
If Not bStop Then
Button1.Text = "Pause"
Else
Button1.Text = "Continue"
End If
End Sub
Private Sub CheckPause()
While bStop And Not bEnd
Application.DoEvents()
End While
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
bEnd = True
End Sub
Private Function YourMethod() As Boolean ' Returning if End is pressed (Button2)
' Callable by timer
ElTimer.Stop()
' Your Code here...
Application.DoEvents()
CheckPause()
If bEnd Then
' Release all Objects, Close all stream and end your application
Return True
End If
ElTimer.Start()
Return False
End Function
End Class
Mark the thread as answered if the answer helps you. This helps others who have the same problem !
Monday, June 22, 2009 3:21 PM
How do I call the private function YourMethod inside of the timer? I think this is getting close to what I am looking for.
Monday, June 22, 2009 3:46 PM
This is certainly the button activity that I wish to have:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Button2.Text = "Start"
Static Downstate As Long
Downstate = Not Downstate
If Downstate Then
Button2.Text = "Pause"
AzTimer.Start()
Else
Button2.Text = "Continue"
AzTimer.Stop()
End If
End Sub
Use 1 button. Button is labeled "Start". After button is pressed, text changes to "Pause". If that button is pressed, loop activity stops and button changes to "continue". This will go on everytime button is pushed.
I think my main stem of confusion (which continues after reading the measuring reaction time post), is how to put this into a seperate thread so that the user still has control over the GUI and can pause/continue whenever he/she wishes.
Monday, June 22, 2009 3:52 PM
Except using bStop and bEnd instead of the downstate long.
Monday, June 22, 2009 3:56 PM
I think my confusion is with this part of the code that you laid out:
Where do I call this boolean? I think this is similar to what Cor was alluding to in his reply, but I am still unsure how to incorporate it.
Private
Function
YourMethod() As
Boolean
' Returning if End is pressed (Button2)
' Callable by timer
ElTimer.Stop
()
' Your Code here...
Application.DoEvents()
CheckPause()
If
bEnd Then
' Release all Objects, Close all stream and end your application
Return
True
End
If
ElTimer.Start()
Return
False
End
Function
Monday, June 22, 2009 4:05 PM
Hi again,
just inside your timer event. Its returning if it should end the programm. Sorry, for the delay of answering, but i have installed a 3th party system, and it does not work :-(Mark the thread as answered if the answer helps you. This helps others who have the same problem !
Wednesday, June 24, 2009 10:10 AM
Hi MBorowski,
if you type application.DoEvents you will see in the tooltip of the intellisense, something like (i have german version) "Processing all windows messages, that are ine the message queue". That means for example if you click a button at the time your code is in the loop or in some long time calculations your application would not "react" anymore on this action. So inserting a Application.DoEvents() just prevent the non reacting.Mark the thread as answered if the answer helps you. This helps others who have the same problem !
Wednesday, June 24, 2009 12:29 PM
Just for some context, many people frown upon the use of Application.DoEvents. I'm not sure of the exact reasoning behind this -- other than effects it could have in a multi-threaded environment -- and I personally am not passionate about the issue. However, I believe you can accomplish the same task by using the Refresh() method on a given control. This is essentially targeting a single area of concern versus clearing the entire message queue.
Wednesday, June 24, 2009 3:08 PM
Thank you so much for the help with background workers.
I am going to assume that I want to run my loop inside 'Do your work
and the 'clean up will be whatever needs to be done to return to the main program?
I am going to read some more about it and tinker with the above code.
Thank you very much.
Matthew
Wednesday, December 21, 2011 11:36 AM
Does no one use DoEvents() anymore?
You can just put it inside your loop and if any keyboard/mouse events occur, they will handled by the routine attached to the event.
Maybe that's too old school for VB.net.