My Kung-fu no good

NauticalGent

Ignore List Poster Boy
Local time
Today, 07:34
Joined
Apr 27, 2015
Messages
6,632
As a follow-up to this post (https://www.access-programmers.co.uk/forums/showthread.php?t=294056) ,

I have gone about as far as I can and could use a hand. The users/clients have asked me to re-establish a way to determine who made the last change to a record and what (fields) were changed. What's more, in the past, they simply just hovered the mouse over the field in the form and it told them who made the change. In the past, this was done in a VERY inefficient manner which caused the underlying tables to have about 2/3 the amount of fields required.

I decided on the Audit Trail mentioned in the link because it seemed the most dynamic and simple.

To give the customer what they asked for and not revive the "monster", I decided to make a Sub that would provide what they wanted from the AuditTable (Which I affectionately re-named "TattleTale")

The Sub:
Code:
Private Sub SetControlTip(ctl As Control)
On Error GoTo err_handler

    Dim dbs As dao.Database
    Dim qdf As dao.QueryDef
    Dim rst As dao.Recordset
    Dim strRec_ID As String
    
    Set dbs = CurrentDb
    Set qdf = dbs.QueryDefs("qrySelectAuditTrail") 'Parameterized query to select info
    strRec_ID = Trim(Str([RECID])) 'Ask me how many times it took me to figure that bit out!
    
    With qdf
        .Parameters("[strRecID]") = strRec_ID
        .Parameters("[strField]") = ctl.Name
        Set rst = .OpenRecordset
        If rst.RecordCount > 0 Then ' Took me a minute to realize I needed this too...
            ctl.ControlTipText = "Old Value: " & rst.Fields(3) & vbCrLf _
            & "New Value: " & rst.Fields(4) & vbCrLf _
            & "Edited By: " & rst.Fields(5)
        Else
            ctl.ControlTipText = "No History"
        End If
    
    End With
    
exit_handler:
    rst.Close          'Lets see if this bit revives some old arguments!
    Set rst = Nothing
    dbs.Close dbs
    Set dbs = Nothing

err_handler
    MsgBox Err.Number & " - " & Err.Description
    Resume exit_handler

End Sub
To call the Sub, I use the following on the MouseMove event:
Code:
Private Sub UpDate_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
     Call SetControlTip(UpDate)
End Sub
If possible, I would like to avoid having to place this Sub on each applicable Field's MouseMove event.

As always, I KNOW I tend to GoAroundMeArse-HoleToGetToMeElbow. With that in mind if there is a better way to achieve this, I am ALL ears (eyes).

Thanks in advance!
 
Last edited:
WithEvents is they key - have a read.

Great article Minty, thanks! I had found something slightly similar in one of my many Dr. Google sessions but it was vague I could not see a way to adapt it to my needs.

This on the other hand is EXACTLY what I am looking for. Once I get it up and running, I will post the final product just in case someone else has the misfortune of needy users who get hit by the "Good Idea" fairly on a frequent basis...

I can see where this will come in handy with many future uses too...

Thanks again!

John
 
Reading it again, I noticed that this is a Class Module to boot...something I have been wanting to learn. Bonus.

I don't care what the rest of AWF says about you, you're Aces with me!
 
You're welcome, I thought it was a very neat methodology, one that I must find a use for :cool:
 
Last edited:
I did...likes like what the Dr ordered. Can't work on it til next week, but I am itching to get at it!
 
@Minty,

Once again, many thanks on sharing that link. I don't know if you had the time to fully explore it, but Gustav offers a link to a Blog that explains With Events and Object Wrapping, Event Sinks and so on.

While in the Blog, there are more entries regarding Class Modules and Code Libraries that I have not seen comiited to 'trons before.

Here is the link: http://jwcolby.blogspot.it

It is laid out in plain language that even I can understand.

Solid assistance given on this one dude. I'd throw some more reputation at you if I could, but the AWF police say I have to spread it around a little more.

Once I get everything put together I will post the complete code here and maybe in the code repository if it passes muster.

Thanks again...
 
Well Minty, as promised attached is a sample of how to do what I was asking for and much more. The link you provided had another link:

http://jwcolby.blogspot.it/2013/02/object-wrappers-and-event-sinks-problem.html

As you will see it walks you through the process of wrapping any form within a class module giving you a dynamic means of handling events for any control.

Unfortunately, the version I did at work is not working correctly (Combo Boxes wont expand) and because it is on a classified machine, I could not upload it or provide myself and copy to work on at home.

So I built a scaled down version and copied JC's code verbatim and of course it works flawlessly. Figured since I took the time to build it, I may as well upload it.

Give it a look, and thanks again for pushing me in the right direction!
 

Attachments

Neat demo , and very easy to see how it's all done. I still haven't had the time to play with this but this is a really good example of how simple it can be, especially for a simpleton like me :)
 
I created a module and added thew code below. (got it from one of the MVP's)
I had to create a table named "audit" with the following fields
EditRecordId autonumber
editdate date/time
User short text
recordid number
sourcedata short text
sourcefield short text
beforevalue short text
aftervalue short text

I have something similar as posted. I then put Call AuditTrail(Me, [Client-ID]) in the before update event of every form. some filed names may have to be changed for your structure

Option Compare Database
Const cDQ As String = """"

Sub AuditTrail(frm As Form, recordid As Control)
Dim ctl As Control
Dim varbefore As Variant
Dim Varafter As Variant
Dim strcontrolname As String
Dim strSQL As String
On Error GoTo errHandler
'Get changed values
For Each ctl In frm.Controls
With ctl
'avoid labels and other controls with value property
' If .ControlType = acCheckBox Then
' MsgBox ("checkbos") '
' End If
If .ControlType = acTextBox Or .ControlType = acCheckBox Or .ControlType = acComboBox Then
If Nz(.Value, "Null") <> Nz(.OldValue, "Null") Then
' If .Value <> .OldValue Then
' varbefore = .OldValue
' Varafter = .Value
varbefore = Nz(.OldValue, "Null")
Varafter = Nz(.Value, "Null")
strcontrolname = .name
'Build Insert into statement
strSQL = "insert into " _
& "audit (Editdate, user, recordid, sourcetable, " _
& " sourcefield, beforevalue, aftervalue) " _
& "Values (Now(), " _
& cDQ & Environ("username") & cDQ & ", " _
& cDQ & recordid.Value & cDQ & ", " _
& cDQ & frm.RecordSource & cDQ & ", " _
& cDQ & .name & cDQ & ", " _
& cDQ & varbefore & cDQ & ", " _
& cDQ & Varafter & cDQ & ")"
'
'View evaluated statement in Immediate Window.
Debug.Print strSQL
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
Else
End If
Else
End If
End With
Next
Set ctl = Nothing

Exit Sub

errHandler:
MsgBox Err.Description & vbNewLine _
& Err.Number, vbOKOnly, "Error"
End Sub
 

Users who are viewing this thread

Back
Top Bottom