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 SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Code to Trigger an event instead of - txtName_LostFocus 1

Status
Not open for further replies.

mb22

Programmer
Sep 4, 2002
258
0
0
US
Instead of say calling .... ( the lost Focus event of a text box.. txtName ).... I'm trying to do programatically
to effect this call......

txtName_LostFocus

'by using this code

Dim objTxtBox As Object
Set objTxtBox = txtName
objTxtBox_LostFocus 'how can I do this programatically?
 
You could give it the focus with SetFocus and move the focus to another control after that.
Greetings,
Rick
 
If you wish to trigger the lostfocus event from somewhere else you can use the Call command

Call objTxtBox_LostFocus
 
I'm trying to do this during Form/Unload..... when exiting the application.

You see this app had all field validation in the lost focus events of each field. So if the user stayed in the field and did not tab away... the lost focus event is not triggered ... and the app exits.

In the form unload... I want to capture the LAST control visited.....
Me.ActiveControl
and then launch the lost focus event for this control.

Setting Focus on the object, and setting focus on another object.. does not trigger it during Form/Unload!!

Call objTxtBox_LostFocus DOES not work either. You get a Compile error... Sub or Function not defined.

But it does exist!!!

Public Sub txtName_LostFocus()
....
End Sub


Moreover objTxtBox has been set to txtName !!!!!!

The problem is how to code the objTxtBox to trigger that call to the lost focus!
 
Try:

Me.ActiveControl.Enabled = False

This should disable the active control, causing it to lose focus and transfer the focus the the next control in the TabIndex order. Not sure that it will work in your situation, but certainly worth a try. BlackburnKL
 
No DID not work! Interesting thought though! I think part of the problem is the form graphical interface is "kind of" unloaded already ...so the controls probably are not there to trigger a lost focus, maybe?

 
I would just cut and paste all of the code into the Validation event.

You could also just cut and paste it into a seperate sub proceedure, and then call that sub proceedure from the Lost focus event AND the Form Unload event.

If you did go the first route, you can call the validation event or call Me.ValidateControls from the form Unload.

[/b][/i][/u][sub]*******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
mbaddoo ..
Move your code to the FormQueryUnload event.
then use the recommendation of Blackburn.
QueryUnload is the typical place to put any clean-up code. and that is what you are trying to do,
I am not at my programming PC so I dont have VB available to write any actual code but if that does not work, how about a Sub that did something like ...

A sub that has a variable to hold the name of the Active control. This Variable MAY have to be Public at the form level, so it can always have the control name. In the Sub put a SelectCase to find the active control. In the SelectCase try to call that controls unload event, if that wont work then have the validation code for each control(If they are different).
From QueryUnload call this Sub.

I know having the same code in 2 places is not the normal method of doing things, but if there is no other way... then its necessary.
Just my thoughts ... sorry I could not provide code.
HTH and its not too confusing.
Micahel
 

[sigh] [/b][/i][/u][sub]*******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Brother the lost focus event does not occur during the form load/unload event.

Choose an alternative method.
 
1.) To reinforce what CCLINT said - use the Validation event for your controls instead of LostFocus. And I also agree that using a single separate validation procedure called from the applicable event is the way to go. You want to avoid repeating code as much a possible.

2.)I don't believe the validate event fires when unloading a form, so you could do something like this to validate the active control. If it's not valid then you would cancel the form unload and set focus to the active control:


Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)



If ValidateActiveControl Then
Cancel = False
Else
Cancel = True
End If

End Sub

Private Function ValidateActiveControl() As Boolean



Dim ctl As Control

Set ctl = ActiveControl

'First make sure we have a control to validate
If TypeOf ctl Is TextBox Then
'I'm checking for a number here
If Not IsNumeric(ctl.Text) Then
ctl.SetFocus 'Set focus to the invalid control
ValidateActiveControls = False
Exit Function
End If
End If

ValidateActiveControl = True

End Function


Hope that helps!
 
Another approach that you can use is to have the event handler call a function which executes the logic. You can then easily call that same function from whenever or where ever is appropriate.

Sub Control_LostFocus
ControlEventHandler
End Sub

Public Function ControlEventHandler
<what ever logic you need>
ControlEventHandler = <return value>
End Sub

From anywhere in the code, you can call ControlEventHandler. Its simply just another function. Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein
 
cclint - I [sighed] with you! [fish] No Dolphins were harmed in the posting of this message... Dolphin Friendly Tuna!
 
Actually, calling Control events from another events/procedure is not good practice. So, CajunCenturion's advise/tip is only one which is absolutely right!
 
Thank you kel1981b for the support.

But if you read the other posts carefully (which I did not do the first time), then you'll see that the suggestion was originally posited by CCLINT. All I did was to throw together some pseudo-code which is an example of the process previously explained. I unfortunately got into saying what I wanted to say, before realizing that I was repeating that which had already been said. Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein
 
>So, CajunCenturion's advise/tip is only one which is absolutely right!

Well, I think I mentioned the same as an option.

But also every one seems to be missing the other mentioned option, which is calling the VB form's ValidateControls method.
That is what it is there for: To cause the last control to fire it's validate event.

>In the form unload... I want to capture the LAST control visited
mbaddoo22:
Move your validation into the control's Validate Event
Then, call the Me.ValidateControls method in the Form_QueryUnload event:

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
On Error Resume Next
Me.ValidateControls
If Err.Number Then
Err.Clear
Cancel = True
End If
End Sub

If the code for validation is in the Validate event of the controls which need validation, then calling the mentioned method will validate the last control which has the focus, or which has not lost the focus. All other controls will have already been validated, as long as the CauseValidation property for each control on the form is set to True.

The correct method would then check to see in the UnloadQuery event if the user wants to save the changes.
This requires of course a class level variable to identify if any changes have been made:

Private m_bPossibleSave As Boolean

This variable is set to true in the Change event of each control which changes data.

Then, in the QueryUnload event, this variable is checked.
If True, the user is asked if they want to save the data.

If yes, the ValidateControls method is called. Note that no seperate proceedure is needed here.
If the ValidateControls returns an error, then the Cancel boolean variable in some controls Validate event was set to True.
The next step, if an error was returned, would be to Cancel the Unload method.

If the ValidateControls method does not return an error, then the Save method is called.

The LostFocus event probably should be left alone, with respect to validation.
If you want the last control with the focus to get validated, then, again, you just call the VB form method ValidateControls.

Now, the last thing that is missing, is the fact that same controls could have invalid data as retrieved from the database (NULL data, etc.).

Here is a bit of an outline on how to expand on this idea. Just drop this into a from and add a textbox called Text1:

Option Explicit
Private m_bPossibleSave As Boolean
Private m_bLoadingData As Boolean 'Used such as when loading the form and data the first time.

'Called from the MDI form
Public Sub Display()
LoadData
Me.Show
End Sub

Private Sub LoadData()
m_bLoadingData = True
'Get data from Db or set default values
Text1.Text = &quot;0&quot;
DoEvents 'make sure control events have had time to take place
m_bLoadingData = False
End Sub

Private Sub Text1_Validate(Cancel As Boolean)
If Not IsNumeric(Text1.Text) Then
MsgBox &quot;You must enter a correct value&quot;
Cancel = True
Text1.Text = &quot;0&quot; 'Default value
Text1.SelStart = 0
Text1.SelLength = Len(Text1.Text)
End If
End Sub

Private Sub Text1_Change()
m_bPossibleSave = Not m_bLoadingData
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Dim Ret As VbMsgBoxResult

If m_bPossibleSave Then
Ret = MsgBox(&quot;Do you want to save the changes?&quot;, vbYesNoCancel)

Select Case Ret
Case Ret = vbNo
'do nothing
Case vbCancel
'About exiting form
Cancel = True
Case vbYes
On Error Resume Next
Me.ValidateControls
If Err.Number Then
Err.Clear
Cancel = True
Else
'All OK, so save the changes. Call the SaveData function to save the changes.
'If this function returns True, then changes were successful. If False, then an error has occured.
If Not SaveData() Then
'Save was not successful.
Cancel = True
End If
End If
End Select
End If
End Sub

Private Function SaveData() As Boolean
'code to Save
SaveData = True
End Function
[/b][/i][/u][sub]*******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Her's how we solved the problem of absolutely positively executing validation (or other code) after a field has been entered or changed.

1. Create a subroutine, we call it
Code:
DoLostFocus
with parameter of
Code:
(SField as String)[code].
2.  Insert Select Case sField, then for each Control insert
[code]Case &quot;Control Name&quot;
3. In each LostFocus event insert
Code:
DoLostFocus (&quot;ControlName&quot;)
.

At this point we have only moved code around. Now comes the reason.

4. Find every place in your code that control can be gained without the lost focus event of the last control being triggered. For us this is mainly tool bar procs and QueryUnload. In each of these places insert
Code:
DoLostFocus Me.ActiveControl.Name
.

We have much milage on this with no complications - and no skipping the lost focus code.


John Kisner


 
Calling a event procedure directly is not good I agree but I also more agree with CCint. The validate event is there for a reason. For those of us that remember a time before this event where bad data in a database would send your code in a infinate loop because of how lost_focus gets triggered. I'm unclear through out this whole thread what the confussion is and why validate was dismissed.

The problem, to be more specific, with lost_focus validation is that if you have field level validation and have 2 fields with data that isn't right for the fields they will loop through endlessly because another control actually gets focus before the lost focus event is fired where as the validate event fires before then. Also this allows you to have a cancel button and not require valid data to cancel out of the form.

While I agree with CajunCenturion's advice as a practice the statement of
&quot;So, CajunCenturion's advise/tip is only one which is absolutely right!&quot; seem a bit extreme and drastic. While we can say in may terms something is totally wrong saying &quot;only one which is absolutely right&quot; does not make sense since CCint suggestion is completely valid in for the purpose and, in my opinion, more appropriate for the situation at hand.
 
ahem... I sighed the collective sigh with cclint long ago... [reading] [fish] No Dolphins were harmed in the posting of this message... Dolphin Friendly Tuna!
 
CCLINT - Thanks. Your solution of:

On Error Resume Next
Me.ValidateControls
If Err.Number Then
Err.Clear
Cancel = True
End If

allowed us to just make a stock change to every form's QueryUnload event when I noticed that closing the form with the form's close button did not execute the _Validate event of the last control to have the focus.

As you noted, Me.ValidateControls does execute the exact _Validate event that needs to be run and, if that event sets Cancel to True, Me.ValidateControls does raise an error which allows _QueryUnload to stop the process of saving any changes and exiting the form.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top