Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Thoughts on DoEvents 1

Status
Not open for further replies.

ToddR

Programmer
Feb 28, 2001
35
US
I understand that Dan Appleman wrote some material on reasons not to use DoEvents. What are the alternatives? Does anyone have any documentation on why DoEvents is bad or what can be used in it's place?
 
I might be wrong but as I understand it if you have one sub in progress at the same time another is working (Eg. a sub oncom in progress reading communications data) the doevents in one routine can affect the other one.
Also if a doevents occurs while an object is being closed and set to nothing I have heard that you might get a memory leak but I havent seen any proof of this.
I have used doevents to show the progressive count of files being inputted with out any problems.
Ted
 
I use doevents when I want to update the form with progress of my program (progress bar, status bar, label etc.) or to allow the user to hit the cancel button and have it register with the program. Other then that I don't see much use for it in VB as the program is contained in it's own thread by the O/S and should(?) not effect other programs that are running.


Troy Williams B.Eng.
fenris@hotmail.com

 
I think Dan was being realistic at the skill level of most VB programmers. Let's face it, most VB programmers are not ready for multi-threaded programming, which is what some will want to use DoEvents for.

I think with the release of VB7 and the CLR, the skill levels of VB programmers will have to increase, otherwise there's going to be a lot of folks shooting themselves in the foot.

Chip H.
 
Personally, I avoid DoEvents at all costs (unless it is absolutely required - the only case might be to allow a screen to refresh during a loop) as I think that it is indicative of a bad implementation.
Some programmers use DoEvents to simulate multi-threading applications which is, in my mind, a misconception. I have been using VB.Net's multithreading function (I have VB.Net Beta 1) and is truly a wonderful thing, but as Chip said, a lot of devlopers will have to increase their skill level - this new version is nothing at all like the current VB.
Just a few thoughts . . .
- Jeff Marler B-)
 
This message is for Jeff marler
If you do not use DOEVENTS what do you use to allow a user to cancel say a
find on a recordset with a find form.
Morgan
 
mgardiner,
Can you post a small piece of code where you are using a DoEvents to cancel a find just so that I make sure that I fully understand how you are using it? Thanks!

- Jeff Marler B-)
 
Actually I haven't gotten the DOEVENTS working for a find on a Recordset.
I was researching why when I ran across this thread that made mention
that there might be a better way. I have seen a couple of threads in here
that mention a possible alternative but no one has posted any code showing
what that alternative might be.
below is my code for my search I would like the user to be able
to select a cancel button and stop the search if possible.
---------------------------------------------------------------------------------------------
Function FindSearch(searchRS As Recordset, findvalue As Variant, FindLookIn As String, _
FindMatch As String, FindDirection As String, Optional FindNextInt As Integer) As Variant
Dim searchfound(3) As Variant
'frmSearch.MousePointer = vbHourglass

With searchRS
.MoveFirst
'.Find (FindLookIn & "= '" & findvalue & "'")
.Find FindLookIn & " like %" & findvalue & "%"
If .BOF Or .EOF Then
MsgBox "Matching Record not Found"
Else
searchfound(0) = searchRS.Fields("ProjectsID")
searchfound(1) = searchRS.Fields("QuoteID")
searchfound(2) = searchRS.Fields("QuoteNoRevision")
End If
End With
FindSearch = searchfound
searchRS.Close

'frmSearch.MousePointer = vbNormal

End Function
-------------------------------------------------------------------------------------------------
Any suggestions would be greatly appreciated.
Morgan
 
When you have a procedure the executes DoEvents you must make sure that you can not enter that DoEvents again though a command click or whatever. I usually disable the button. To cancel, the cancel button sets a flag or execute a method that sets a flag that the running procedure can "see" after DoEvents.
Code:
Private mblnCancel as boolean
Sub cmdLoopIt_Click()
    cmdLoopit.Enabled = false
    cmdCancel.Enabled = true
    ' Must not reach here twice
    Do While (mblnCancel = false)
        DoEvents
    Loop
    cmdCancel.Enabled = false
    cmdLoopit.Enabled = true
    mblnCancel = false
End Sub 
Sub cmdCancel_Click ()
    mblnCancel = true
End Sub
' You can also use the same button
Private mblnCancel as boolean
Private mblnBusy as boolean
Sub cmdLoopIt_Click()
    if mblnBusy then 
        mbnlCancel = true
        cmdLoop.Enabled = false
        cmdCaption = "Wait"
        exit sub
    End if
    mblnBusy = true
    cmdLoopit.Caption = "Cancel"
    ' Must not reach here twice
    Do While (mblnCancel = false)
        DoEvents
    Loop
    cmdLoop.Caption = "Loop"
    cmdLoop.Enabled = true
    mblnCancel = false
    mblnBusy = false
End Sub
 
Thank You for the Information on DOEVENTS.
I was still wondering if for my particular application is there
a better or alternative way to cancel the find once it has started.
Morgan
 
To: John Yingling
I used your code sample and modified it to fit my code as follows.
I still cannot stop the Find methode of the ADO Recordset once it is started
to the SQL server.
Is there a way of stopping it. Any help would be appreciated.
Also I have found that even though I reference an Previous connection
in my connection string I still get another connection showing on my SQL
2000 server any Ideas.
Morgan


Public mblnCancel As Boolean
Public mblnBusy As Boolean


Private Sub cmdFindCancel_Click()
If mblnBusy Then
mblnCancel = True
cmdFindCancel.Caption = "Find"
'mblnBusy = False
Exit Sub
End If

mblnBusy = True
'mblnCancel = False
cmdFindCancel.Caption = "Cancel"
' Must not reach here twice
Call Findtext(cboFindWhat.Text, cboLookIn.Text, cboMatch.Text, cboSearchDirection.Text)

mblnCancel = False
mblnBusy = False
cmdFindCancel.Caption = "Find"
End Sub


Function Findtext(findvalue As Variant, FindLookIn As String, _
FindMatch As String, FindDirection As String, Optional FindNextInt As Integer) As String
Dim adoQuoteRS As Recordset
Dim SearchDataType As Integer
Dim searcharray() As Variant

'create a recordset to search on
Dim strsql As String
Set adoQuoteRS = New Recordset
strsql = "SELECT tblQuotes.*, tblQuoteLog.*, tblProjects.* " & _
"FROM tblProjects " & _
"INNER JOIN tblQuotes ON tblProjects.ProjectsID = tblQuotes.ProjectID " & _
"INNER JOIN tblQuoteLog ON tblQuotes.QuoteID = tblQuoteLog.QuoteID"

adoQuoteRS.Open strsql, g_objConn, adOpenDynamic, adLockOptimistic

'Find out what field FINDLOOKIN is equal to and what datatype it is
If FindLookIn <> &quot;Entire Database&quot; Then
'find what datatype the field is
'there are many unused types listed here I just listed all of the possibilities
Select Case adoQuoteRS.Fields(FindLookIn).Type
Case Is = 0 'adEmpty=0
Case Is = 200 'adVarChar=200
searcharray() = FindSearch(adoQuoteRS, findvalue, FindLookIn, FindMatch, FindDirection)
Call QuoteLogViewSearch(searcharray)
End Select
Else

End If

Exit Function








Function FindSearch(searchRS As Recordset, findvalue As Variant, FindLookIn As String, _
FindMatch As String, FindDirection As String, Optional FindNextInt As Integer) As Variant
Dim searchfound(3) As Variant
'frmSearch.MousePointer = vbHourglass


Do While (frmSearch.mblnCancel = False)
DoEvents
Select Case FindMatch
Case Is = &quot;Any Part Of Field&quot;
If FindNextInt = 1 Then
With searchRS
Select Case FindDirection
Case Is = &quot;All&quot;
.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;, 1
Case Is = &quot;Up&quot;
.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;, 1, adSearchBackward
Case Is = &quot;Down&quot;
.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;, 1, adSearchForward
End Select
'.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;
If .BOF Or .EOF Then
MsgBox &quot;Matching Record not Found&quot;
Else
searchfound(0) = searchRS.Fields(&quot;ProjectsID&quot;)
searchfound(1) = searchRS.Fields(&quot;QuoteID&quot;)
searchfound(2) = searchRS.Fields(&quot;QuoteNoRevision&quot;)
End If
End With
Else
With searchRS
Select Case FindDirection
Case Is = &quot;All&quot;
.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;
Case Is = &quot;Up&quot;
.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;, , adSearchBackward
Case Is = &quot;Down&quot;
.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;, , adSearchForward
End Select
'.Find FindLookIn & &quot; like %&quot; & findvalue & &quot;%&quot;
If .BOF Or .EOF Then
MsgBox &quot;Matching Record not Found&quot;
Else
searchfound(0) = searchRS.Fields(&quot;ProjectsID&quot;)
searchfound(1) = searchRS.Fields(&quot;QuoteID&quot;)
searchfound(2) = searchRS.Fields(&quot;QuoteNoRevision&quot;)
End If
End With
End If
End Select
frmSearch.mblnCancel = True
Loop


FindSearch = searchfound
searchRS.Close
end function
 
First of all, I do not recommend reaching across to a form to pick up a public variable. The cancel routine should &quot;reach down&quot; via a called SUB to set a locally accessible variable to &quot;CANCEL=True&quot;. That aside, I see that the DO - Loop is not really looping. You check once at the beginning to see if CANCEL has been &quot;ordered&quot; and at the end set mblnCancel. In that case it is clearer to
Code:
Do While(frmSearch.mblnCancel = false)
........
    Exit Do
Loop
because later code may need to know that a true CANCEL occurred.
I see that you do not chck for CANCEL after the
adoQuoteRS.Open strsql, g_objConn, adOpenDynamic, adLockOptimistic
Why not? At least it will short circuit the FIND.
I gave the Do While as an example of some long running iterative process that would issue DoEvents to determine if it should be interrupted. In your case you are issuing ONE .FIND which is apparently taking all the time and is not interruptable. Unless there is a .CANCEL or .STOP method (like with the WebBrowser), you will not come out of the .FIND until it is done. My example was along the lines of YOUR reading a large file, record by record and YOUR checking for CANCEL after every read.
Code:
Do While(mblnCancel = false)
    DoEvents
    if mblnCancel then exit do
    Read
    if eof then exit do 
    ...process
Loop
If the object you are using does not have a CANCEL or STOP method then you are out of luck. I would look for a way to iteratively perform the FIND in &quot;chunks&quot; so that you could check for CANCEL every once in a while.

I see a CANCEL method RDO objects but it applies to ASYNCHROUNOUS operations which might have its own set of problems.
&quot;Cancel Method (Remote Data)
See Also Example Applies To

Cancels the processing of a query running in asynchronous mode, or cancels any pending results against the specified RDO object.

Syntax

object.Cancel

The object placeholder represents an object expression that evaluates to an object in the Applies To list.

Remarks

The Cancel method requests that the remote data source stop work on a pending asynchronous query or cancels any pending results. In some cases, it might not be possible to cancel an operation once it is started, and in other cases it might be possible to cancel the operation, but part of its steps might have already been completed.

In situations where you need to create a result set, but do not want to wait until the query engine completes the operation, you can use the rdAsyncEnable option with the OpenResultset or Execute method. This option returns control to your application as soon as the operation is initiated, but before the first row is ready for processing. This gives you an opportunity to execute other code while the query is executed. If you need to stop this operation before it is completed, use the Cancel method against the object being created.

The Cancel method can also be used against an rdoConnection object when you use the rdAsyncEnable option to request an asynchronous connection. In this case the attempt to connect to the remote server is abandoned.

You can also use the Cancel method against a synchronous rdoResultset or rdoQuery object to flush remaining result set rows and release resources committed to the query and rdoResultset.

If you use the Cancel method against rdoResultset objects that have multiple result sets pending, all result sets are flushed. To simply cancel the current set of results and begin processing the next set, use the MoreResults method.

Note Using the Cancel method against an executing action query might have unpredictable results. If the query is performing an operation that affects a number of rows, some of the rows might be changed, while others are not. For example, if you execute an action query containing an SQL UPDATE statement and use the Cancel method before the operation is complete, an indeterminate number of rows are updated — leaving others unchanged. If you intend to use the Cancel method against this type of action query, it is recommended that you use transaction methods to rollback or commit partially completed operations.&quot;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top