-
Aug 9th, 2014, 08:30 PM
#1
Thread Starter
Hyperactive Member
[RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
I want to have a countdown on the screen.
I used to do something like this:
Code:
For x = 3 To 1 Step -1
lblMsg.Text = x
'Delay
For y = 1 To 40000
doevents()
Next y
Next x
lblMsg.text = "go!"
without the delay, the "countdown" is instantaneous.
I need to inject a delay to simulate "3.....2.....1.....Go"
-
Aug 9th, 2014, 09:03 PM
#2
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
Do NOT use DoEvents() in this situation!
There are a few alternatives for you:
- Use a timer at a set interval and set the text of your label in the Tick event
- Use the Threading.Thread.Sleep() method to create a short "pause" in your code
Because you're doing a simple countdown then I'd suggest option 1, using the Threading.Thread.Sleep() method causes the UI thread to become unresponsive during it's sleeping period which makes the program look as if it's frozen. Here is an example of using a countdown timer:
Code:
Public Class Form1
Private countdown As Integer
Private lblMsg As Label
Private tmr As System.Windows.Timer
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
'Globals
countdown = 3
'Controls
lblMsg = New Label With {.AutoSize = True, .Location = New Point(5, 5), .Text = countdown.ToString}
tmr = New System.Windows.Timer With {.Interval = 1000} '1 second timer
'Events
AddHandler tmr.Tick AddressOf tmr_Tick() 'Add the tick event
'We don't want an empty form
Me.Controls.Add(lblMsg)
'Go go go!
tmr.Start()
End Sub
Private Sub tmr_Tick(ByVal sender As object, ByVal e As EventArgs)
countdown -= 1
If countdown = 0 Then tmr.Stop()
lblMsg.Text = countdown.ToString()
End Sub
End Class
-
Aug 9th, 2014, 10:28 PM
#3
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
Spinning around DoEvents is called a busy wait, which is a terribly bad thing to do for a variety of reasons. While the busy wait is looping, the CPU is maxed out, which noticeably increases power consumption by the computer, and subsequently increases heat output, while also slowing down all other processes on the system. That's why it's a bad thing to do.
My usual boring signature: Nothing
-
Aug 10th, 2014, 10:02 AM
#4
Thread Starter
Hyperactive Member
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
dday9, minor point, but I think your code won't display the "3" ....
Here is how I coded it up with the timer!
Code:
If count = 0 Then
lblMsg.Text = "Go!"
tmrCountdown.Enabled = False
Else
lblMsg.Text = count
count = count - 1
End If
-
Aug 10th, 2014, 10:03 AM
#5
Thread Starter
Hyperactive Member
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
PS: It's interesting to see dday9 do his entire UI in run-time.
I guess this is how .NET has really become a true OOP lang like Java, C++, etc.
-
Aug 10th, 2014, 10:35 AM
#6
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
He does that simply so that the code can be copied and pasted without needing to tell the OP, "First, put these components on a form then name them like so." Normally, the only reason to build the interface dynamically is if you need to add the controls dynamically, which is rare, but DDay likes to provide examples that contain both the controls he is using AND the code to manipulate them.
Having said that, there's nothing special about the designer. Every form has a .designer.vb file associated with it. Unless you have created a custom constructor, this file will have the contructor in it (Sub New), and the definition of the InitializeComponents() method, which has to be the first call in any form constructor. If you look at InitializeComponents(), you will see all the controls being constructed and their properties being set. That's all the designer does: Manipulates the code in that function. The controls are just objects like any other, and they are created like any other object. Perhaps the only oddity to them is that they are all added to a .Controls collection for them to be visible, but they are just objects the same as every other object. Generally, you wouldn't want to mess around with the .designer.vb file, because if you do the wrong thing, the designer will cease to work, though you can recover it by fixing your mistake...as long as you can identify your mistake.
Something like that was done in VB6, except that the controls were all part of a file that was effectively written in a different language that was interpreted. Those files weren't XML, but in concept, it was similar to XAML in that the file described what was needed in a language unlike the language the rest of the code was written in. The real difference with .NET is that the controls, their layout, and the form they are on, are all written in the same language as the rest of the code, which makes them much easier to tinker with, since you only need to know one language.
My usual boring signature: Nothing
-
Aug 10th, 2014, 01:57 PM
#7
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
Originally Posted by RipVoidWinkle
PS: It's interesting to see dday9 do his entire UI in run-time.
I guess this is how .NET has really become a true OOP lang like Java, C++, etc.
He would not normally.
-
Aug 11th, 2014, 07:16 AM
#8
PowerPoster
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
DoEvents only makes the program then goto the next lines after a certain section of source code has been processed by the IDE, while in RunTime or even CompileTime. So then that wouldn't work. I guess that you are looking for the main idea of something holding back the lines of source code being processed by the program, while in either RunTime or even CompileTime. So then the best bet for this problem is to have the Timer on a Interval loop, counting down the milliseconds in the Timer's presetup Interval property that has been setup in DesignTime, however you are also able to setup the values in the property, also at RunTime and CompileTime, however it just makes more sense to do that if you can in DesignTime, it just makes a lot less programming to do, while the computer is processing the program source coded lines...
I have a huge free products range, of computer software in which you can download using any kind of 64-Bit Web Browser. Also there is coming a Social Networking section that I am making on my Website...
|Ambra Productions Inc. | The Black Sun Society | The Black Shield | Ambra College | Church of the Black Sun | Ambra Productions Inc's Homepage | Boomtick Event's Venues: Ambar Nightclub, Jack Rabbit Slim's, Villa Nightclub and Lucy's Bar | Pasta Ambra | Fish Feast Company | Wallet Wizard | Ambrose Liquor | Ambar Tavern | Ambra University |
Do you wish to do unpaid work for me??? If so, the PM me on this Forum, and then we can get to work, programming for the future of computers go by the name of ThEiMp. This is my ghost writers name. Also my nickname, means that I am: The Imperial of the Technology Industry, so then to make it really short, I just then wrote: The Imp, which is where I get the nickname from...
-
Aug 11th, 2014, 07:18 AM
#9
PowerPoster
Re: I used to use Huge Loop & DoEvents() to create an artificial delay. Alternative?
Originally Posted by dday9
Do NOT use DoEvents() in this situation!
There are a few alternatives for you:
- Use a timer at a set interval and set the text of your label in the Tick event
- Use the Threading.Thread.Sleep() method to create a short "pause" in your code
Because you're doing a simple countdown then I'd suggest option 1, using the Threading.Thread.Sleep() method causes the UI thread to become unresponsive during it's sleeping period which makes the program look as if it's frozen. Here is an example of using a countdown timer:
So sorry I didn't see your post when I had sent mine, in...
I have a huge free products range, of computer software in which you can download using any kind of 64-Bit Web Browser. Also there is coming a Social Networking section that I am making on my Website...
|Ambra Productions Inc. | The Black Sun Society | The Black Shield | Ambra College | Church of the Black Sun | Ambra Productions Inc's Homepage | Boomtick Event's Venues: Ambar Nightclub, Jack Rabbit Slim's, Villa Nightclub and Lucy's Bar | Pasta Ambra | Fish Feast Company | Wallet Wizard | Ambrose Liquor | Ambar Tavern | Ambra University |
Do you wish to do unpaid work for me??? If so, the PM me on this Forum, and then we can get to work, programming for the future of computers go by the name of ThEiMp. This is my ghost writers name. Also my nickname, means that I am: The Imperial of the Technology Industry, so then to make it really short, I just then wrote: The Imp, which is where I get the nickname from...
-
Aug 11th, 2014, 08:23 AM
#10
Thread Starter
Hyperactive Member
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
I just ran into another situation where I need a short pause...
I don't think I can use a timer, b/c this is not like a countdown.
There is no action to be taken except a short pause.
How would I use Threading.Thread.Sleep() ?
How long of a pause will that give me?
Will that vary across different CPU machines?
-
Aug 11th, 2014, 08:32 AM
#11
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
Sleep takes a number of milliseconds as an argument, so you can set how long it pauses, and the pause will be pretty precise regardless of CPU. However, when a thread sleeps it gives up its processing time, which means that if you sleep the UI thread then it won't paint the screen. This will mean that the app will appear frozen and unresponsive during the time it is sleeping. For this reason, Sleep is almost never the right answer for the UI thread.
For pauses greater than 50 milliseconds, the best solution is a timer, but that requires thinking about code a bit differently. People often want a routine to be contained in a single method, as you had in the original post, where it does something, pauses for a time, then does something else. Sleep does that, except that the UI is frozen for the duration. With a timer, there would be two methods. The first method would start the timer (which might be ALL that it does), then the timer code fires every time the interval elapses. You can stop the timer or change the interval in that timer code, so it's pretty flexible, but the code to start the timer is not located in the same method as the code that occurs when the timer ticks.
My usual boring signature: Nothing
-
Aug 11th, 2014, 09:05 AM
#12
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
There is no action to be taken except a short pause.
JMcIlhinney has a codebank contribution... here. It does exactly what you're wanting to do and it doesn't have the negative side effects like Threading.Thread.Sleep() can have.
-
Aug 11th, 2014, 09:07 AM
#13
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
Hi,
To expand on what has already been said by SH and ONLY if you are using .NET4.5 you can use Async and Await to write "in-line" code which can implement a Pause, using Tasks which execute on another Thread, thereby keeping the UI thread responsive.
Have a play with these two examples of creating Tasks and see if you can expand on them to make them work for what you need:-
vb.net Code:
Public Class Form1
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Counter = 10 To 1 Step -1
TextBox1.Text = Counter.ToString
Await SomePauseUsingTaskWithSub()
Next
MsgBox("Done!")
For Counter = 10 To 1 Step -1
TextBox1.Text = Counter.ToString
Await SomePauseUsingTaskWithAddressOf()
Next
MsgBox("Done!")
End Sub
Private Function SomePauseUsingTaskWithSub() As Task
Return Task.Run(
Sub()
Threading.Thread.Sleep(1000)
End Sub)
End Function
Private Function SomePauseUsingTaskWithAddressOf() As Task
Return Task.Run(AddressOf CreatePause)
End Function
Private Sub CreatePause()
Threading.Thread.Sleep(1000)
End Sub
End Class
Hope that helps.
Cheers,
Ian
-
Aug 11th, 2014, 09:32 AM
#14
Thread Starter
Hyperactive Member
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
I actually want the UI to freeze.
Here is my context:
I have a pictureBox the user clicks.
When clicked, the picture changes to pic #2, the viewer sees it for 1-2 seconds, and then the pictureBox is hidden.
If these 2 lines of code are run back to back, the card is hidden before the user can see pic#2.
It just looks like the card is hidden when clicked, b/c the code runs so fast.
I tried this, but it doesn't work.
The delay happens before the picture is shown.
It seems like the thread sleeps (Step #2) before the picture is ever loaded in step #1.
Yet, how did the code get to the sleep part if the image is not yet loaded from Step #1?
Code:
' Step 1: Change pic
index = cardsArray.ToList().IndexOf(sender)
cardsArray(index).Image = pics(index)
' Step 2: NEED A DELAY
Threading.Thread.Sleep(1000)
'Step 3: Hide card.
cardsArray(index).Visible = False
Last edited by RipVoidWinkle; Aug 11th, 2014 at 09:36 AM.
-
Aug 11th, 2014, 09:43 AM
#15
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
Hi,
I actually want the UI to freeze.
No you don't because that's what's causing your problem!, This implies that you probably do not really understand the concept of Multi Threading? In your case you Need the UI Thread to Keep being responsive to complete the Drawing of the image but also add a Pause as the same time. This simply CANNOT be done on the same Thread so you need to try one of the examples posted by the members that have responded to this Thread.
Cheers,
Ian
-
Aug 11th, 2014, 11:12 AM
#16
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
I have a pictureBox the user clicks.
When clicked, the picture changes to pic #2, the viewer sees it for 1-2 seconds, and then the pictureBox is hidden.
That's simple enough. What you should do is whenever the user clicks the PictureBox, change it's picture to picture #2 and start the timer, then after the elapsed time, set it back to what it was. A timer is still suitable for this:
Code:
Public Class Form1
Private pbCard As PictureBox
Private tmr As Timer
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
'Controls
pbCard = New PictureBox With {.Location = New Point(5, 5), .Image = My.Settings.Picture1}
tmr = New Timer With {.AutoReset = True, .Interval = 1500} '1 and 1/2 second timer
'Events
AddHandler pbCard.Click, AddressOf pbCard_Click() 'Add the click event for the PictureBox
AddHandler tmr.Elapsed AddressOf tmr_Tick() 'Add the tick event for the Timer
'We don't want an empty form
Me.Controls.Add(pbCard)
End Sub
Private Sub pbCard_Click(ByVal sender As Object, ByVal e As EventArgs)
'Start the timer if it's not already running
'Also change the image
If Not tmr.Enabled Then
pbCard.Image = My.Settings.Picture2
tmr.Start()
End If
End Sub
Private Sub tmr_Tick(ByVal sender As object, ByVal e As EventArgs)
'Change the image back to what it was
pbCard.Image = My.Settings.Picture1
End Sub
End Class
-
Aug 11th, 2014, 11:44 AM
#17
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
I agree with DDay, but want to expand a bit on what IanRyder said. The problem you are encountering is that changing the picture doesn't actually change the picture you see. When you change the image, the control invalidates its display area, which means that a paint event is posted to the message queue. The painting won't actually happen until that paint message is pumped from the queue, and pumping the queue can't happen while the UI thread is doing other things (including sleeping). So, while you did change the image with that line of code, the new image won't actually be drawn onto the screen until after the method ends, which means after the sleep has finished and the other lines have completed (one of which hides the picturebox, so the net result is that the picturebox is hidden). Normally, the method will finish so fast that it looks like the painting happens as part of the method, but it really doesn't happen until after the method.
So, while DDay has the best solution (since I really dislike freezing the UI), there is another alternative that should work, which is to force the picturebox to redraw as soon as the image changes and not wait for the paint event to be handled. This can be done with:
cardsArray(index).Refresh
There is also an .Invalidate, which allows the control to redraw when the UI gets around to it, but that's what's already happening when you change the image. The .Refresh method forces the control to redraw right then, before the next line of code is executred. I seem to remember cases where I had to call it twice, but once should work just fine.
My usual boring signature: Nothing
-
Aug 11th, 2014, 05:06 PM
#18
Thread Starter
Hyperactive Member
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
I will try out dday's method as well,
but Shaggy's quick hack works, and that is good enough for now !
Code:
' Step 1: Change pic
index = cardsArray.ToList().IndexOf(sender)
cardsArray(index).Image = pics(index)
cardsArray(index).Refresh()
' Step 2: NEED A DELAY
Threading.Thread.Sleep(1000)
'Step 3: Hide card.
cardsArray(index).Visible = False
-
Aug 11th, 2014, 05:14 PM
#19
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
Not exactly a hack. That point is often essential. If you have a long running process and you want to inform the user about where they are at by updating a label, it doesn't help when the changes to the label don't happen until after the long running process has ended. The difference between .Refresh and .Invalidate is this:
.Refresh: DO IT NOW!!!!
.Invalidate: Do it when you get a chance.
Sometimes, you just have to be pushy.
My usual boring signature: Nothing
-
Aug 11th, 2014, 07:50 PM
#20
Thread Starter
Hyperactive Member
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
I thought V is single threaded.
When do you have a long running process where you invoke a 2nd thread to give an update?
Is this stuff with the timer?
-
Aug 11th, 2014, 08:04 PM
#21
Re: [RESOLVED] I used to use Huge Loop & DoEvents() to create an artificial delay. A
Originally Posted by Shaggy Hiker
The difference between .Refresh and .Invalidate is this:
.Refresh: DO IT NOW!!!!
.Invalidate: Do it when you get a chance.
Sometimes, you just have to be pushy.
Not exactly. Refresh actually calls Invalidate internally. Specifically, the Invalidate method says "next time you paint, repaint this area". If you don't specify an area then the whole control bounds is assumed. It's possible to call Invalidate multiple times before a single paint to repaint composite areas. The Update method says "repaint all invalidated areas now". The Refresh method simply calls Invalidate with no arguments and then calls Update. If you want to force an immediate repaint of just a particular area then you don;t call Refresh but rather call Invalidate and pass an appropriate argument and then call Update.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|