-
Dec 10th, 2017, 05:09 AM
#1
Thread Starter
Member
Proper way to end a program with Timer controls
I would have expected clicking on the command button to end the following program but all it does is to cause the window to disappear while the process continues indefinitely.
If you wan to see it for yourself, it just contains a timer control , a command button and a text box.
Edit: Sorry I should have added my question, what is the proper way to end this program?
Code:
Option Explicit
Private Sub Command1_Click()
Timer1.Interval = 0
Unload Me
End Sub
Private Sub Timer1_Timer()
Static alreadyhere As Boolean
If Not alreadyhere Then
alreadyhere = True
Dim c As Long
For c = 1 To 50000
Text1.Text = c
DoEvents
Next
alreadyhere = False
End If
End Sub
Last edited by C++Novice; Dec 10th, 2017 at 05:55 AM.
-
Dec 10th, 2017, 06:04 AM
#2
Re: Proper way to end a program with Timer controls
Try with a termination flag like this
vb Code:
Option Explicit
Private m_bTerminated As Boolean
Private Sub Command1_Click()
m_bTerminated = True
Unload Me
End Sub
Private Sub Timer1_Timer()
Dim c As Long
Static alreadyhere As Boolean
If Not alreadyhere Then
alreadyhere = True
For c = 1 To 50000
Text1.Text = c
DoEvents
If m_bTerminated Then
Exit Sub
End If
Next
alreadyhere = False
End If
End Sub
cheers,
</wqw>
-
Dec 10th, 2017, 01:38 PM
#3
Addicted Member
Re: Proper way to end a program with Timer controls
Seems to me that you missing stop the timer when m_bTerminated = true
-
Dec 10th, 2017, 03:04 PM
#4
Thread Starter
Member
Re: Proper way to end a program with Timer controls
Thanks wqw
That does the trick all right.
-
Dec 10th, 2017, 03:52 PM
#5
Thread Starter
Member
Re: Proper way to end a program with Timer controls
Hi I am back again, sorry!
Your solution works wqw but what about situations like in the slightly altered code below, where the DoEvents call is inside a nested procedure and the outer procedure later updates a control? If the nested procedure was called in many different places or nested deeply it could become a big chore making
sure there was no possibility of a control being referenced and preventing the process from ending.
I am not trying to be smart but just looking to understand this better or get guidance for dos and donts in general.
Code:
Option Explicit
Private m_bTerminated As Boolean
Private Sub Command1_Click()
m_bTerminated = True
Unload Me
End Sub
Private Sub Timer1_Timer()
Static alreadyhere As Boolean
If Not alreadyhere Then
alreadyhere = True
Nested_Procedure
Text1.Refresh 'added this to trigger form load
alreadyhere = False
End If
End Sub
Private Sub Nested_Procedure()
Dim c As Long
For c = 1 To 50000
Text1.Text = c
DoEvents
If m_bTerminated Then
Exit Sub
End If
Next
End Sub
-
Dec 11th, 2017, 02:32 AM
#6
Re: Proper way to end a program with Timer controls
You can prevent form reloading with
vb Code:
Private Sub Form_Load()
If m_bTerminated Then
Unload Me
End If
End Sub
This way you can trap "Object was unloaded" error in the IDE when control usage after termination is not guarded by m_bTerminated flag and impl sanity checks.
Calling out DoEvents and/or raising events can lead to all sorts of reentrancy complications, incl. form being unloaded by client code.
cheers,
</wqw>
-
Dec 11th, 2017, 02:54 AM
#7
Thread Starter
Member
Re: Proper way to end a program with Timer controls
Originally Posted by wqweto
You can prevent form reloading with
vb Code:
Private Sub Form_Load() If m_bTerminated Then Unload Me End If End Sub
This way you can trap "Object was unloaded" error in the IDE when control usage after termination is not guarded by m_bTerminated flag and impl sanity checks.
Calling out DoEvents and/or raising events can lead to all sorts of reentrancy complications, incl. form being unloaded by client code.
cheers,
</wqw>
Thanks wqw, that's clever.
I am going to play with this for awhile.
Until recently I wasn't aware of how much can go wrong when using doevents and I have probably tended to use it too much.
I think maybe it's a really bad idea to have a doevents inside a timer, more so than in other places?
-
Dec 11th, 2017, 05:03 AM
#8
Fanatic Member
Re: Proper way to end a program with Timer controls
why not just "END" instruction inside the Timer code? it is buggy?
-
Dec 11th, 2017, 05:28 AM
#9
Thread Starter
Member
Re: Proper way to end a program with Timer controls
Originally Posted by flyguille
why not just "END" instruction inside the Timer code? it is buggy?
I believe that it is a bad idea to use "End" (i could be wrong though), and that the proper way is to unload all the forms in your application as in something like the following:
Code:
Private Sub Shutdown()
Dim F As Form
For Each F In Forms
Unload F
Next
End Sub
-
Dec 11th, 2017, 09:58 AM
#10
Re: Proper way to end a program with Timer controls
Originally Posted by flyguille
why not just "END" instruction inside the Timer code? it is buggy?
Hi Flyguille,
The problem is, you don't execute your Form_Unload events or your Class_Terminate events. In addition, if you're doing subclassing or any OS hooking, you're quite possibly not gracefully backing out of that either.
Given those things, using the "End" statement can easily crash the VB6 IDE, and it can possibly even crash Windows under specific circumstances. Truth be told, even using the "End" button on the VB6 IDE isn't entirely advisable (although, with care, I'll admit that I often do that).
I've heard someone describe the "End" statement as comparable to snatching the key out of a simi-truck barreling down the interstate and throwing them out the window. C++Novice has shown you how to find an exit ramp and pull into a truck-stop.
Here's some code to test and see what I'm saying.
Code:
Option Explicit
Private Sub Form_DblClick()
End
End Sub
Private Sub Form_Terminate()
MsgBox "terminate COM"
End Sub
Private Sub Form_Unload(Cancel As Integer)
MsgBox "unload"
End Sub
Good Luck,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Dec 11th, 2017, 05:11 PM
#11
Re: Proper way to end a program with Timer controls
I always use End, but with caution.
in the Form_Unload you set Cancel = 1, this will break the unloading,
now, you do whatever you need to stop subclassing/unloading/set nothing etc.
also, if you are using components/apis that require some "time" to end, you need to wait until its done,
at the very end of the line, a nice and destructive "End".
the problem with "End" is that it used before some stuff are terminated/closed/ended, like subclassing.
that is why we use WM_NCDESTROY, to avoid such problems.
but its better to stop the subclassing manually.
and of course, as Elroy pointed out, we can create crashes if we run different things simultaneously.
but if you are doing it right, end should not give you any problems. at least not for me.
-
Dec 11th, 2017, 05:30 PM
#12
Re: Proper way to end a program with Timer controls
End isn't quite as drastic as some think:
The End statement stops code execution abruptly, without invoking the Unload, QueryUnload, or Terminate event, or any other Visual Basic code. Code you have placed in the Unload, QueryUnload, and Terminate events of forms and class modules is not executed. Objects created from class modules are destroyed, files opened using the Open statement are closed, and memory used by your program is freed. Object references held by other programs are invalidated.
But:
The End statement provides a way to force your program to halt. For normal termination of a Visual Basic program, you should unload all forms. Your program closes as soon as there are no other programs holding references to objects created from your public class modules and no code executing.
I can't remember using End in over 15 years. Use the recommended route described above.
-
Dec 11th, 2017, 06:05 PM
#13
Re: Proper way to end a program with Timer controls
that is why you create a "termination" function, that will do important cleanups before you call end.
i have used end over 15 years without any issues.
its quite amusing that some are afraid of using end.
Text1.Refresh will not trigger Form_Load!
if you want to avoid api's and just want to play with vb timer, i would:
Private Sub Command1_Click()
Form_Unload 1
End Sub
Private Sub Timer1_Timer()
Dim c As Long
Timer1.Enabled = False
For c = 1 To 50000
Text1.text = c
DoEvents
If m_bTerminated Then Exit Sub
Next c
Timer1.Enabled = True
End Sub
Private Sub Form_Unload(Cancel As Integer)
Cancel = 1
m_bTerminated = True
' other cleanups, save function, etc '
End
End Sub
the reason I call Form_Unload is that you can use the button or the "x" button.
inside the timer, i simply stop the timer, do the for/next and start the timer again.
also, depending what you want to do and how fast it is, but just running a loop its quite pointless and to call a doevent for each number?,
i would try to update every 10, 100 or even 1000 instead of each one.
also, better use Label instead of Textbox.
-
Dec 11th, 2017, 06:07 PM
#14
Re: Proper way to end a program with Timer controls
-
Dec 12th, 2017, 09:56 AM
#15
Re: Proper way to end a program with Timer controls
Originally Posted by baka
that is why you create a "termination" function, that will do important cleanups before you call end.
i have used end over 15 years without any issues.
its quite amusing that some are afraid of using end.
You know what you're doing. So does Dill... so do I... problem is that a lot of the people around here don't. So you can't leave the door open even just a crack for things like that. If someone starts to think it's ok to use End in one situation, they start thinking it's OK to use it any time they want, as long as they are careful... then they forget... that one time they aren't careful... and take the easy way out...
Same thing happens with On Error Resume Next ... I advocate not using it for the same reasons... it makes it too easy for people to paint themselves into a corner they don't understand and can't get out of. It's not that any of it is evil (which we've been accused of as well) or that we're afraid of it, it's that we know better and we've got painful battle scars we'd just rather others not have to experience. We've done the bare foot fire walk and this is us telling the others, hey look, fireproof boots.
And that's why you get so much push back on some of your advice. It make work for you, but it simply isn't safe for some of the others around here. Not to mention those that stumble into the middle of the thread from a search that don't have the benefit of having read the entire thread, or all of your posts where you've noted the lengths you've gone to. And that's what the problem is.
-tg
-
Dec 12th, 2017, 10:11 AM
#16
Re: Proper way to end a program with Timer controls
no, we should not hold hand. programming is progress and learning.
why tell people to not do something because it could get ugly? no, let people try and figure it out.
im with you with on error, but its not that we can avoid it completely. sometimes it's useful. but we add it because we are 100% certain whats going on, not because we don't have a clue and we put it there to avoid errors.
and thats the point, we want to learn "how to use it", not to "avoid and never learn about it".
its quite silly that you assume people are ignorant and need protection. its not fatal to do mistakes and mess up.
again, you put unneeded fears into peoples mind and after a while people start spreading those fears around and people believes they need to follow and in the end, they don't learn, they just avoid. bravo.
-
Dec 12th, 2017, 10:23 AM
#17
Thread Starter
Member
Re: Proper way to end a program with Timer controls
Thanks everyone. Your method looks interesting Baka but as techgnome says, I don't know enough to feel confident enough to use it.
Also is it not losing one of the advantages that vb gives us over languages where you have to manually dispose of stuff?
In my software I have a timer that regularly checks a database for tasks to do, most of which would have been added remotely.
There might be 0, 1, 100s or rarely 1000s of tasks added and it loops through them.
There's doevents in there to allow the user to do stuff in the program at the same time.
The timer was so as to have it happen automatically, the doevents so as not to tie stuff up on the user.
It's worked away fine as far as I can see but just it's dawned on me that I am very likely doing it wrong.
I should probably fire the timer more often and limit it to a task or two per timer event rather than relying on doevents or does
it make any practical difference?
-
Dec 12th, 2017, 11:09 AM
#18
Re: Proper way to end a program with Timer controls
End, is a way to tell VB its time to halt everything and close, it will not trigger Unload, QueryUnload, and Terminate.
No matter if we are using Unload Me or a custom termination procedure, we need a Cleanup (usually we have modules, references, classes etc)
In a big project, it could be that the "cleanup" don't work, maybe a references API/Object is not responding.
In this case, End will break that reference and force the program to terminate.
sometimes it is better to spread around the calls instead of calling all procedures inside a loop.
example:
we call 10 different procedures in a timer, using:
for i = 1 to 10: call procedure i: next i
that would call all 10 in a sequence, each time the timer is triggered
but we could also do:
static i&
i = i + 1
if i = 11 then i = 1
call procedure i
that way, each time the timer is triggered, it will call 1 procedure (we need to adjust the interval)
doing so, we avoid the "loop" freezing and maybe we don't need DoEvents at all.
-
Dec 12th, 2017, 11:12 AM
#19
Re: Proper way to end a program with Timer controls
Originally Posted by C++Novice
Thanks everyone. Your method looks interesting Baka but as techgnome says, I don't know enough to feel confident enough to use it.
Also is it not losing one of the advantages that vb gives us over languages where you have to manually dispose of stuff?
In my software I have a timer that regularly checks a database for tasks to do, most of which would have been added remotely.
There might be 0, 1, 100s or rarely 1000s of tasks added and it loops through them.
There's doevents in there to allow the user to do stuff in the program at the same time.
The timer was so as to have it happen automatically, the doevents so as not to tie stuff up on the user.
It's worked away fine as far as I can see but just it's dawned on me that I am very likely doing it wrong.
I should probably fire the timer more often and limit it to a task or two per timer event rather than relying on doevents or does
it make any practical difference?
Hi,
I posted this in another thread, and it always worked for me.
here the sample..
Code:
Option Explicit
Private NextAction As Date
Private Interval As Long
Private IntervalType As String
Private Sub Command1_Click()
Dim i As Long
'next full hour
i = Hour(Now)
Interval = 1
IntervalType = "h"
NextAction = DateAdd(IntervalType, Interval, Date + CDate(i & ":00:00"))
Timer1.Interval = 1000
Timer1.Enabled = True
Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
Command4.Caption = "Stop"
End Sub
Private Sub Command2_Click()
Dim i As Long
'every 10sec.
Interval = 10
IntervalType = "s"
NextAction = Now
Timer1.Interval = 1000
Timer1.Enabled = True
Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
Command4.Caption = "Stop"
End Sub
Private Sub Command3_Click()
Dim i As Long
'every 2min.
Interval = 2
IntervalType = "n"
NextAction = Now
Timer1.Interval = 1000
Timer1.Enabled = True
NextAction = DateAdd(IntervalType, Interval, Date + CDate(i & ":00:00"))
Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
Command4.Caption = "Stop"
End Sub
Private Sub Command4_Click()
Timer1.Enabled = False
Command4.Caption = "Stopped"
End Sub
Private Sub Form_Load()
Command1.Caption = "every hour"
Command2.Caption = "every 10sec."
Command3.Caption = "every 2min."
Command4.Caption = "Stopp"
End Sub
Private Sub Timer1_Timer()
Dim s As String
s = "Countdown " & Format(NextAction - Now, "hh:nn:ss")
If NextAction > Now Then
If Label1.Caption <> s Then
Label1.Caption = s
End If
Exit Sub
End If
NextAction = DateAdd(IntervalType, Interval, Now)
Timer1.Enabled = False
'your action here
List1.AddItem "Action " & Format(Now, "dd.mm.yy hh:nn:ss")
Timer1.Enabled = True
Label2.Caption = Format(NextAction, "dd.mm.yyyy hh:nn:ss")
End Sub
regards
Chris
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
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
|