SQL*Forms Tech Tip - Using Color

From: Daniel Druker <ddruker_at_us.oracle.com>
Date: Fri, 22 May 1992 00:13:20 GMT
Message-ID: <1992May22.001320.3527_at_oracle.us.oracle.com>


 COLORING FIELDS DYNAMICALLY BY ATTRIBUTE Steve Muench, Tools Sup.



 It is often desirable to communicate information to the SQL*Forms  operator visually, by using different video attributes. For example,  one might wish to have the enterable fields in Reverse Video, while  the fields which the operator cannot change in Bold. The DISPLAY_FIELD  packaged procedure allows us to dynamically alter the display attributes  for given fields in our form, but what we seek is an intelligent  mechanism to systematically be able to "color" fields based on certain  attributes.

 We begin by remarking that the packaged function FIELD_CHARACTERISTIC  gives us any information that we might like to know about how a  particular field is defined. In particular, if we know the name of a  field, say 'EMP.EMPNO', FIELD_CHARACTERISTIC can return the name of the  next field in sequence in the current block. It can also tell us whether  or not 'EMP.EMPNO' is an enterable field, has a List-Of-Values  associated to it, is a database field, and much, much more. We'll take  advantage of this in the procedure we develop below.

 Let's assume that we are developing a form based on the EMP table, in  which the SAL and COMM fields are non-enterable. Our goal is to display  the employee records to the operator in such a way as to have the  non-enterable fields (SAL and COMM) be in Bold, while all of the  enterable fields remain in their normal video display attribute.

 Since video attributes are individual to each particular record, we will  need to color each record retrieved from the database. A POST-QUERY  trigger would be a good place for such behavior. We could write a  procedure which colors the SAL and COMM fields Bold, and then call that  procedure from our POST-QUERY trigger. Such a procedure might take the  form:

	 PROCEDURE color_non_enterable_fields IS
	 BEGIN
	   DISPLAY_FIELD('emp.sal', 'Bold');
	   DISPLAY_FIELD('emp.comm','Bold');
	 END;

 However, this procedure will only work in our current form, and in  particular will only work in the EMP block of our current form. If the  need arose to color non-enterable fields bold in another form, we would  be forced to rewrite a form/block-specific procedure like the one above.  This takes time and again would only be solving a particular problem for  a single form.

 It is apparent that a more generic procedure is necessary. We will set  our sights on developing a single procedure which will work in any form  we might ever create -- with any blocks, and any fields that the future  may have in store. It's noble purpose will be that of coloring all the  non-enterable fields in the current block to Bold.

 The algorithm that we shall adopt is straightforward:

    (1) Determine the first field of the current block.     (2) For each field in the current block

     | (2a) Determine if the field in question is ENTERABLE.
     | (2b) If (No), then color the field in question Bold.
     |_(2c) Determine the next field in sequence to consider

 For step (1), we can use the BLOCK_CHARACTERISTIC packaged function.  In fact, if 'EMP' is the name of the current block, then  BLOCK_CHARACTERISTIC('EMP',FIRST_FIELD) gives the name of the first  field in the 'EMP' block.

 Using the FIELD_CHARACTERISTIC packaged function, we can perform steps  (2a), (2b), and (2c). If 'EMP.EMPNO' is the name of the field currently  under consideration, then FIELD_CHARACTERISTIC('EMP.EMPNO',ENTERABLE)  will evaluate to the string 'TRUE' if EMPNO is enterable, and the  string 'FALSE' if not. This solves (2a) and (2b).

 For (2c) we note that FIELD_CHARACTERISTIC('EMP.EMPNO',NEXTFIELD)  gives the name of the next field in sequence in the 'EMP' block  immediately following 'EMPNO'. In the case that we ask for the  NEXTFIELD for the field which is the last in sequence,  FIELD_CHARACTERISTIC will return NULL, because technically speaking  there is no 'Next' field.

 So our procedure appears to be coming together. Take the following  example below:


	 PROCEDURE color_non_enterable_fields IS
	   /*

|| Declare local variables
*/ cur_field CHAR(80); cur_block CHAR(40); BEGIN /*
|| Store the name of the current block, and use
|| it to determine the first field in that block.
*/ cur_block := :SYSTEM.CURSOR_BLOCK; cur_field := BLOCK_CHARACTERISTIC(cur_block,FIRST_FIELD); LOOP /* || If the current field we're considering is || NOT Enterable, then color it bold. */ IF FIELD_CHARACTERISTIC(cur_field,ENTERABLE) = 'FALSE' THEN DISPLAY_FIELD(cur_field,'Bold'); END IF; /* || Determine the name of the next field to || consider, and EXIT the LOOP if NULL. */ cur_field := FIELD_CHARACTERISTIC(cur_field,NEXTFIELD); IF cur_field IS NULL THEN EXIT; END IF; END LOOP; END; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 We did it! Using the procedure above, we can color all of the  non-enterable fields bold in any block in any form. We make no  assumptions about the name of the current block, and we have carefully  avoided hardcoding the names of any of our fields into the procedure  itself. We've saved ourselves time and needless rewriting of code to  perform a useful task in an arbitrary number of occasions.

 However, with this noble milestone in our rearview mirror, we might be  tempted to ask ourselves, "Have we really written our procedure in the  most generic way possible?" Perhaps we set our sights too low, and a  still nobler aspiration lies within our reach? Of course we can do  better.

 There is nothing sacred about the 'ENTERABLE' field attribute which we  have chosen for our example above. In fact, this is just one of many  possible field attributes which might interest us. The complete list  includes:

	       AUTO_HELP      FIXED_LENGTH     UPDATEABLE
	       AUTO_SKIP      LIST             UPDATE_NULL   
	       BASE_TABLE     PRIMARY_KEY      UPPER_CASE
	       ECHO           QUERYABLE
	       ENTERABLE      REQUIRED


 Our procedure above is written in a generic fashion, but still only  allows us to color fields based on whether they are ENTERABLE or not.  Since for any particular field, the FIELD_CHARACTERISTIC function can  give us information about any or all of the above list of attributes,  we should not make the assumption that our future needs will be  satisfied by just using the ENTERABLE attribute. We will make our  procedure work for any of the possible cases.

 While we are thinking of ways to make the procedure even more flexible  and generic, let's consider why we hardcoded the product attribute  'Bold' into our procedure. This was not necessary. Why not let the  designer specify what attribute to color the fields? This way we could  use the same procedure to color fields 'Bold-Inverse-Underline' in one  case, and simply 'Bold' in another case without changing the procedure  itself.

 Also, the curious reader may have questioned our choice of coloring  the field(s) when they did NOT possess a particular attribute -- being  not ENTERABLE, in our initial problem. We have found another piece of  logic which could be generalized. We should allow the designer to  specify whether to color fields WITH a particular attribute, or  WITHOUT it as the need arises.

 Therefore, our list of "enhancements" has quickly grown to include:

     (1) Allow the designer to specify the name of the field attribute 
	 upon which to base our coloring decision.

     (2) Allow the designer to specify whether to color fields which 
	 POSSESS or DO NOT POSSESS the attribute specified in point (1)

     (3) Allow the designer to specify the name of the product
	 attribute with which to "color" the fields identified by the 
	 criteria established in points (1) and (2)

 By taking advantage of the fact that PL/SQL procedures support the  passing of parameter values, we can "parametrize" all three of our  features above. We will rewrite the procedure above to include three  parameters:

           (1) The name of the attribute to test.

	   (2) A boolean value of TRUE or FALSE which will determine
	       whether to color fields which possess the attribute
	       named in (1) or those which DO NOT possess it.

	   (3) A string containing the name of the product attribute
	       name to use when "coloring" the fields in question.

 The names of the attributes are actually internally declared, numeric  PL/SQL constants. That is, the SQL*Forms developers have assigned an  arbitrary number to each of the possible field attributes and  pre-defined the numeric constants AUTO_HELP, AUTO_SKIP, BASE_TABLE,  etc. So the first parameter will be of type NUMBER to allow the  passing of this numeric constant.

 The second parameter will be of type BOOLEAN, because we only need to  pass a True or False. The third parameter will need to be of type  CHAR, to pass the product attribute name.

 Our much-enhanced, more generic procedure assumes the form:


	 PROCEDURE color_fields (attrib_const    NUMBER,
				 color_condition BOOLEAN,
				 prod_attrib     CHAR    ) IS
	   /*

|| Accepts parameters:
||
|| NAME TYPE DESCRIPTION
|| -------------- -------- ------------------------------
|| attrib_const NUMBER Numerical value of PL/SQL
|| constant representing one
|| of the valid field attributes
||
|| color_condition BOOLEAN Either True or False
||
|| prod_attrib CHAR Name of Product Attribute
|| || ||
|| Declare local variables
*/ cur_field CHAR(80); cur_block CHAR(40); field_possesses_attrib BOOLEAN; BEGIN /*
|| Store the name of the current block, and use
|| it to determine the first field in that block.
*/ cur_block := :SYSTEM.CURSOR_BLOCK; cur_field := BLOCK_CHARACTERISTIC(cur_block,FIRST_FIELD); LOOP /* || Using the PL/SQL numerical constant passed in || the parameter 'attrib_const', set the BOOLEAN || variable 'field_possesses_attrib' to True if the || field under consideration possesses the given field || attribute. Otherwise, 'field_possesses_attrib' is || set to False. */ field_possesses_attrib := (FIELD_CHARACTERISTIC(cur_field,attrib_const) = 'TRUE'); /* || If the BOOLEAN 'field_possesses_attrib' matches that || specified by the Boolean parameter 'color_condition', || then color the field according to the product || attribute name supplied in the 'prod_attrib' parameter */ IF (field_possesses_attrib = color_condition) then DISPLAY_FIELD(cur_field,prod_attrib); END IF; /* || Determine the name of the next field to || consider, and EXIT the LOOP if NULL. */ cur_field := FIELD_CHARACTERISTIC(cur_field,NEXTFIELD); IF cur_field IS NULL THEN EXIT; END IF; END LOOP; END; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 After adding our more ambitious procedure above to one of your  favorite forms, experiment away! For example, I created a simple form  based on the EMP table, typed in the procedure above, and added the  following POST-QUERY trigger on the EMP block:

	 color_fields(AUTO_HELP,FALSE,'Underline');
	 color_fields(UPPER_CASE,TRUE,'Bold');
	 color_fields(LIST,TRUE,'Bold-Inverse');

 This changes the display attributes of any of the fields in the  current block to:

	 UNDERLINE      if they DO NOT have an Auto Hint message,
	 BOLD           if they are marked as Uppercase Only,
	 BOLD-INVERSE   if they have an associated List of Values.

 In this bulletin, we've seen that we can save development time in the  long run by devising ways to generalize useful functionality into  Form-Level procedures which accept parameters. When teamed with the  mechanism which SQL*Forms 3.0 provides to Reference objects from one  form stored in the database to any other form you create, the time  saved can really add up.

 REFERENCES:
 (*) "Packaged Functions" -- SQL*Forms Designer's Reference,

                              Version 3.0, Chapter 17
 (*) "PL/SQL Procedures" -- SQL*Forms Designer's Reference,

                              Version 3.0, Chapter 15
 (*) "Product Attributes" -- Oracle*Terminal User's Guide,

                              Version 1.0, Appendix B

  • Dan

Daniel Druker
Senior Consultant
Oracle Corporation                    


| Dan Druker                    |  work 415.506.4803                          |
| oracle*mail ddruker.us1       |  internet: ddruker_at_us.oracle.com            |
-------------------------------------------------------------------------------

Disclaimer: These are my opinions and mine alone, and don't reflect the views or position of my employer. Received on Fri May 22 1992 - 02:13:20 CEST

Original text of this message