Originally published in FoxTALK February 1999
When Does It Happen?
In developing applications in Visual FoxPro we are always depending on events being processed. Every keystroke and mouse click is critically important to the proper functioning of the application. How much do you actually know about when things happen in Visual FoxPro? This month we will examine some of the important events and find out exactly when they occur.
Events and methods
First, before a venture into the events that fire during various operations in Visual FoxPro, let’s classify the events and methods that are available in the product. My preference is to refer to these code-locations as event-methods and methods. The difference between an event-method and a simple method is how it is fired. A simple method only fires if a line of code has called it, it may have default behavior built into VFP or it may simply be a place where you can write code and then call that code when needed.
An event-method is automatically fired based on some event occurring, for example the KeyPress event-method of a control will automatically fire whenever the user presses a key while focus is in that control. It is important to differentiate between the event (pressing a key) and the event-method (KeyPress) that fires as a result of the event occurring. Calling an event-method in program code does not cause the associated event to occur. It simply runs the code in that event-method.
Getting and losing focus
There are a number of event-methods and methods associated with a control receiving and/or losing focus. The event-methods related to receiving and losing focus are When (event-method), GotFocus (event-method), SetFocus (method), Valid (event-method), and LostFocus (event-method).
To take the best advantage of the event model in Visual FoxPro it is necessary to clearly understand the event-methods that fire and the point in time that they fire. In the process of receiving focus the sequence of event-methods is 1 – When and then 2 – GotFocus.
The When event-method can be thought of as the place to determine whether or not focus will be allowed to arrive at the control. Returning a value of .F. from the When event-method will prevent focus from arriving at the control. Once the When event returns a value of .T., the GotFocus will fire (if the When returns .F. the GotFocus does not fire). The GotFocus can be classified as the event-method in which you prepare for the control to receive focus, since it only fires if the control is going to receive focus.
The SetFocus method also plays a role in that it has the default behavior of beginning the process of receiving focus for a control. A control’s SetFocus method is similar to the FoxPro 2.X _curobj variable.
There are two controls that act slightly different in respect to the When event-method, these are the ListBox and the ComboBox. With these two controls, the When fires as it does for other controls, as focus arrives at the object and before the object actually receives focus. The When can return .F. to prevent focus from arriving on that object.
However, with lists and combos, the When also fires every time the currently selected item changes. Because of this behavior, it is important to be careful with what code you put in a list or combo’s When event-method. You should be aware that the When will fire multiple times for these two controls as the user navigates through their list.
The process of losing focus is similar. There are two event-methods involved, Valid and LostFocus. The Valid fires first and can be used to prevent focus from leaving the control. A return of .F. from the Valid will cause the control to retain the focus. A return of .T. from the Valid will allow focus to leave the control and thusly will fire the LostFocus. Like the When and GotFocus, the Valid can be used to decide if focus should be allowed to leave the control and the LostFocus can be used to react to a control losing focus.
Visual FoxPro is a data management tool and as such it has some very powerful and easy to use data binding capabilities. Many of the controls in VFP are able to be bound to a data source by setting the value of the control’s ControlSource property. Using the ControlSource property causes a control to automatically update the ControlSource when the value of the control is changed.
However, like anything else in life, the updating of the ControlSource takes place at a specific point in time. Knowing exactly when the update occurs is critical to getting the most flexibility out of the controls in Visual FoxPro.
There have been a number of questions that have arisen regarding what some folks want to classify as “bugs” related to the updating of a ControlSource. One such situation was for a developer that was issuing a THISFORM.Refresh() in the InteractiveChange event of a textbox and was complaining because the textbox kept reverting to the original value of the ControlSource. Others have found that using a GetFldState(-1) from a button in a toolbar does not reflect the changes made in the control that had focus when the toolbar button was clicked.
Neither of these are “bugs”, they are both “by design”. What!?
Yes, the design for the controls in VFP is that they update their ControlSource with their Value immediately before their Valid event fires. If the Valid event does not fire then the ControlSource has not been updated.
In the previous section we discussed the Valid event and found that it fires in response to a control attempting to lose focus. In the former situation, the InteractiveChange, the control is not losing focus, so its Valid does not fire and its ControlSource retains the original value. The call to refresh the form causes the control to also be refreshed and the control, during its refresh, rereads its ControlSource (which still has the original value).
In the latter situation, the toolbar button, the problem is found in the fact that toolbars and menus never receive focus. Since the toolbar never got focus the control never lost focus, its Valid never fired and its ControlSource did not get updated.
Before we look at solutions, let’s run a small test to see the effects of this behavior. In this test create a form with a textbox that is ControlSourced to a field in a table. Then go into each of the following events and enter;
DEBUGOUT “<Event Name> ControlSource: “ + EVALUATE(THIS.ControlSource) ;
+ “Value: “ + THIS.Value
Replace the <Event Name> with the name of the particular event-method you place the code in. Place this line of code in the GotFocus, InteractiveChange, KeyPress, Valid, and LostFocus event-methods.
Then open the debugger and run the form. Type a new value into the textbox and then press Tab to exit the textbox. In the DEBUGOUT window of the debugger you will see results that are similar to the table below.
Notice, in the table, that there is a period of time when the value in the ControlSource is not the same as the Value of the control. If you were to refresh the control during this time, the value of the control would be reverted to the then current value of the ControlSource.
If you did not press the Tab key at the end of the data entry, but instead clicked a toolbar button or selected a menu option. The textbox would still retain the focus. This means the Valid would not fire and the ControlSource would not be updated. If the code executed by the toolbar button (or menu option) used GetFldState(-1) to check for changed fields it would not see that current field as having been changed. This is because the field has not been changed yet.
The solution is to force the current control to update its ControlSource in any code in a toolbar button or menu option that will be using GetFldState() or TableUpdate(). You can do this by simply calling the SetFocus of that control. Calling the SetFocus of the control causes Visual FoxPro to first fire the Valid and LostFocus event-methods before firing the SetFocus method. Thus the control will update its ControlSource.
You must use some caution when doing this though. There is always the possibility that the current form has no current control or that the current control does not have a SetFocus method. The code example below shows how you can check for these situations.
IF TYPE(“_screen.ActiveForm.ActiveControl.Name”) = “C”
* The rest of your code goes here
The code above first checks the data type of the Name property for the active control in the currently active form. If the Name property is character then we can safely assume the ActiveControl is an object. The second IF checks to see if the ActiveControl has a SetFocus method, if it does have one we call it. Calling the SetFocus causes the lose focus process to occur firing the Valid and LostFocus event-methods and updating the ControlSource.
Why is this stuff so non-intuitive?
Why doesn’t this stuff work the way I think it should? Why is it so weird? Well, its weirdness is a relative issue, to some folks this behavior may seem weird to others it seems like the best way for things to work. One person’s food is another person’s poison.
The important thing in this article is the testing that was done. The results are only descriptive of an event model for a particular set of processes in Visual FoxPro. Being able to create a listing of events and the state of things during those events is the real benefit of this article.
You can try to memorize every nuance of Visual Foxpro if you like. I don’t think you will ever know them all and I also don’t think it is a good use of time to memorize the quirks of any particular tool. It is, however, a very good use of time to leave an application development project for a few minutes and build a small test form to study what is going on in a given situation. Then return to the project and code it according to what you learned during the test.