This is the third and final part of a series presenting a proposal for the use of the tag property of DataWindow columns. My original thought was to provide a means to automatically set a microhelp for each column. Of course, if you are using an MDI application you have a function to set the microhelp, but that function is only available in MDI. If you are using any other application type, then this is not available to you.
Even if you do have an MDI, I have found that the microhelp is not as useful as I would like. The microhelp is always on the frame, nowhere near the column. The user might miss it entirely.
In order to implement something that might be a bit more useful, we created several objects in our tool library that, when used together, will give us the functionality that we seek. You will need those objects to reproduce what we are doing here. If you don't have them from previous articles you will still be able to find them in the downloadable source code for this article.
First we have to consider what we want to do. One of the most common things that I like to do is associate a "pre" and "post" event to a DataWindow column. We can set it up so that we have an event that we use before the column gets focus, sort of like the preOpen and the postOpen events of a window in the PFC. To do that we need to be able to have two different values in the tag attribute. One is good for naming the pre-event and the other the post.
Of course the very first thing is to decide upon the metaphor. How do we want to distinguish the pre-event from the post? We have a tag, which is a string. How do we separate the values?
On the one hand we could use the ini file metaphor, key=value. We would still be left with the problem of multiple values. We could do something like this:
Pre-event=ue_pre_focus;post-event=ue_post_focus
I prefer another style that I picked up somewhere:
[pre_event]ue_pre_focus[post_event]ue_post_focus
We will need to expand our DataWindow object to load all of the key/value pairs into our key_value pair object when the column is getting focus.
Start with a DataWindow
The first thing that we need is a DataWindow that will give us something reasonable to use. Let's do an employee editor DataWindow.
Create a new DataWindow with a freeform presentation style. It will need a SQL Select data source. Select all the columns and then sort them by last name and first name.
Of course the DataWindow will need to be formatted. It doesn't look good at all. The emp_id should be read-only so let's make that a computed field.
We need to create a drop down for both the department and the manager fields. They are IDs but if we make a drop down DataWindow, they can display the names. So we'll need two new DataWindows. I like to name these dddw_department and dddw_employee because I may want to reuse them elsewhere. It's a good idea to put them in their own pbl so you can always find them quickly. I'm putting them in my tools pbl.
Both of the drop downs will be read-only so let's remove all the columns and add a computed field. The computed field for the employee drop down has this expression:
‘(‘ + emp_id + ‘) ‘ + emp_lname + ‘, ‘ + emp_fname
The drop down DataWindow for the department is a little more complex but not too bad. You need to select the department name from the department table. In the department table you'll find a column named dept_head_id. Use that to join to the employee table and get the name of the department head (see Figure 1).
Figure 1
Note that if you first choose the department table, then the employee, your join will be on the dept_id. You will need to change that. If you open the employee table first, then the join will be what you want.
Finally order this by department name. Then you delete all the objects off the DataWindow painter and add a computed field. Here's my expression:
department_dept_name + ‘ (‘ + employee_emp_lname + ‘, ‘ + employee_emp_fname + ‘)'
After we format the DataWindow, we put it into a window and retrieve it. Of course that window needs to be opened from our application open event.
Let's add a static text under the DataWindow. We'll use that for our test. Your window should look something like Figure 2.
Figure 2
Finally We Get to the Point of the Articles
What we really need is an event that will act like the rowFocusChanging
event but for columns. Let's create that. We need to pass that event the column that we are leaving and the one to which we are going. We do this in u_dw
and start by adding an instance variable to hold the last column that we were in. When we have done that these will be our instance variables:
U_dw instance variables
private string is_selection_mode = "n"
private n_cst_dw_row_helper idw_row_helper
private u_dw_microhelp io_microhelp
private boolean ib_microhelp_registered = FALSE
private string is_last_column = ""
n_cst_key_value_collection io_key_values
Note: the last variable will be used later in this article. Bear with me.
We will use the is_last_column
to store the last column we were in. As you can see, it's initialized to an empty string. The next thing we need to do is create an itemFocusChanging
event like the rowFocusChanging
. It doesn't need any code. It just needs to be there and accept two string variables. Here's the code for it:
U_dw. itemFocusChanging
Now we need to call this column from the ItemFocusChanged
event. Here is the code:
u_dw.ItemFocusChanged
IF ib_microhelp_registered then io_microhelp.text = dwo.tag
trigger event itemFocuschanging( is_last_column, dwo.name)
is_last_column = dwo.name
So now we have an event that will allow us to handle both leaving a column and entering into it. This is just what we need.
Automating Our Events
The next thing is to add code to our new event that checks for a tag in both columns. If we have a "post" event tag in the old, then we do that first. Then we check to see if there is a pre-event tag in the new column and do that one.
There is a little twist to this event. We don't know how many commands we might have on the tag. We could have just one, or both, or at some time in the future we may have many. Here is where we need the key / value object. Look in the tools pbl and you will find n_cst_key_value_collection
. Once again, if you don't have the tools.pbl then you can download it or email me and I'll send it to you.
There are only two functions in this object that concern us. We will need of_add
and of_value
. We call of_add from the itemFocusChanging
event.
As I considered what I was going to do I realized that I missed an essential function in the key value object when we created it. I forgot to add a function that lets me clear the object so it can be reused. Let's open that object and add the of_clear
function:
n_cst_key_value_collection.of_clear
ids_key_value.reset( )
Here is where we use that mysterious instance variable that I spoke of before, the lo_key_values
. It will hold the values on the tag for the current object. First we have to create it. We do that in the constructor of u_dw
:
Constructor of u_dw
io_key_values = create n_cst_key_value_collection
Now in itemFocusChanging
we add the code that makes all this work.
U_dw. itemFocusChanging
if io_key_values.of_count() > 0 then
string ls_event, ls_tag
ls_event = io_key_values.of_value( "post_event")
if len(ls_event) > 0 then triggerevent(ls_event)
end if
io_key_values.of_clear()
ls_tag = this.describe(as_new_column + ".Tag")
if len(ls_tag) > 0 then
int li_left, li_right, li_next_left
string ls_key, ls_value
li_left = pos(ls_tag, "[")
do while li_left > 0
li_right = pos(ls_tag, "]", li_left)
if li_right > 0 then
ls_key = mid(ls_tag, li_left + 1, li_right - li_left - 1)
li_next_left = pos(ls_tag, "[", li_right)
if li_next_left > 0 then
ls_value = mid(ls_tag, li_right + 1, li_next_left - li_right - 1)
else
ls_value = right(ls_tag, len(ls_tag) - li_right)
end if
io_key_values.of_add(ls_key, ls_value)
li_left = li_next_left
else
li_left = -1
end if
loop
end if
ls_event = io_key_values.of_value( "pre_event")
if len(ls_event) > 0 then triggerevent(ls_event)
Almost Done
Basically we are in fact done, but we need a test. Go back to your d_employee
DataWindow. Go to the emp_fname
column and put this in the tag:
[pre_event]ue_pre[post_event]ue_post
Finally open w_main. Add two new events to dw_1
. Call one ue_pre and the other ue_post. Put a messagebox in each. Now run your application. When you enter the first name field the ue_pre
event will fire. When you leave the column the ue_post
event will fire.
Obviously you could have as many events as you like. You can have a ue_pre_name
, ue_prev_city
, etc. You can go farther too. You can add other types of tag commands. All the commands will automatically be in the key value object. You can just add functionality for them in your itemFocusChanging event.
Oh yeah, that brings up one other thing - I bet you'll find a lot of uses for the itemFocusChanging
event other than the tag values.