I received a message after publishing the No More Number Indicators story about an alternate method of conditioning fields in a Display file without using indicators. As the person who sent me this did so as Anonymous I cannot thank them by name, but you know who you are.
I did use this method once, many years ago. I had create a program and display file for the editing of UB82 and UB92, universal billing forms used by hospital and doctors to submit to Medicare and other insurance companies. To put all of the fields on screens made it look too confusing and complicated. Therefore, I tried to make it easier to understand by only displaying the field relevant to the type of claim, highlighted the fields in error, etc. Before long I found I was using just about all of the indicators, *IN01 - 99, on the first couple of record formats. What was I going to do for the rest?
A look in the IBM manual for programming with displays introduced me to Program to Systems fields. By passing a hexadecimal value to a field in the display file I could eliminate most of the indicators I had been using.
In this example PFLD001 is defined as a Program to System field, see line 3 below. This is defined as a single byte alphanumeric field, with 'P' for the field Use. The DSPATR on line 2 indicates that the field FLD001 is conditioned by the field PFLD001.
01 A R SCREEN1 02 A FLD001 3A B 2 2DSPATR(&PFLD001) 03 A PFLD001 1A P |
All I have to do is move the appropriate hexadecimal value to PFLD001, see below, and that will change the way FLD001 is displayed. Below is how I could do it in RPGLE/RPG IV using the hexadecimal code for red and reverse image:
01 FDISPLAYF CF E WORKSTN 02 /free 03 PFLD001 = x'29' ; 04 exfmt SCREEN1 ; |
One of the display attributes I used in this program was the Position Cursor, DSPATR(PC), which is not handled with Program to System fields. Therefore, if the user wanted to move to the next field in error they would press F2, the key I designated for this purpose, and I had to use indicators to position the cursor to the next field.
So what are all of the hexadecimal values that can be used for Program to System fields, and what are they the equivalent of:
Hex | Color COLOR() |
Display attribute DSPATR() |
Displayed as |
20 | GRN | Green | |
21 | GRN | RI | Green, reverse image |
22 | WHT | White | |
23 | WHT | RI | White, reverse image |
24 | GRN | UL | Green, underline |
25 | GRN | UL RI | Green, underline, reverse image | 26 | WHT | UL | White, underline |
27 | ND | Nondisplay | |
28 | RED | Red | |
29 | RED | RI | Red, reverse image |
2A | RED | HI | Red, high intensity |
2B | RED | HI RI | Red, reverse image, high intensity |
2C | RED | UL | Red, underline |
2D | RED | UL RI | Red, unline, reverse image |
2E | RED | UL BL | Red, underline, blink |
2F | ND | Nondisplay | |
30 | TRQ | CS | Turquoise, column separator |
31 | TRQ | CS RI | Turquoise, column separator, reverse image |
32 | YLW | CS | Yellow, column separator |
33 | WHT | RI CS | White, reverse image, column separator |
34 | TRQ | UL CS | Turquoise, underline, column separator |
35 | TRQ | UL RI CS | Turquoise, underline, reverse image, column separator |
36 | YLW | UL CS | Yellow, underline, column separator |
37 | ND | Nondisplay | |
38 | PNK | Pink | |
39 | PNK | RI | Pink, reverse image |
3A | BLU | Blue | |
3B | BLU | RI | Blue, reverse image |
3C | PNK | UL | Pink, underline |
3D | PNK | UL RI | Pink, underline, reverse image |
3E | BLU | UL | Blue, underline |
3F | ND | Nondisplay |
Hex | Color COLOR() |
Display attribute DSPATR() |
Displayed as |
A0 | GRN | PR | Green, protected |
A1 | GRN | PR RI | Green, protected, reverse image |
A2 | WHT | PR | White, protected |
A3 | WHT | PR RI | White, protected, reverse image |
A4 | GRN | PR UL | Green, protected, underline |
A5 | GRN | PR UL RI | Green, protected, underline, reverse image | A6 | WHT | PR UL | White, protected, underline |
A7 | ND PR | Nondisplay, protected | |
A8 | RED | PR | Red, protected |
A9 | RED | PR RI | Red, protected, reverse image |
AA | RED | PR HI | Red, protected, high intensity |
AB | RED | PR HI RI | Red, protected, reverse image, high intensity |
AC | RED | PR UL | Red, protected, underline |
AD | RED | PR UL RI | Red, protected, unline, reverse image |
AE | RED | PR UL BL | Red, protected, underline, blink |
AF | ND PR | Nondisplay, protected | |
B0 | TRQ | PR CS | Turquoise, protected, column separator |
B1 | TRQ | PR CS RI | Turquoise, protected, column separator, reverse image |
B2 | YLW | PR CS | Yellow, protected, column separator |
B3 | WHT | PR RI CS | White, protected, reverse image, column separator |
B4 | TRQ | PR UL CS | Turquoise, protected, underline, column separator |
B5 | TRQ | PR UL RI CS | Turquoise, protected, underline, reverse image, column separator |
B6 | YLW | PR UL CS | Yellow, protected, underline, column separator |
B7 | ND PR | Nondisplay, protected | |
B8 | PNK | PR | Pink, protected |
B9 | PNK | PR RI | Pink, protected, reverse image |
BA | BLU | PR | Blue, protected |
BB | BLU | PR RI | Blue, protected, reverse image |
BC | PNK | PR UL | Pink, protected, underline |
BD | PNK | PR UL RI | Pink, protected, underline, reverse image |
BE | BLU | PR UL | Blue, protected, underline |
BF | ND PR | Nondisplay, protected |
Rather than use the hexadecimal codes it would make it easier to understand if they are given meaningful names. If I was to use them again I would create a datastructure that would look like this:
* Program To System Fields D PgmToSys DS qualified * Fields will be unprotected D GRN 1A inz(x'20') D GRN_RI 1A inz(x'21') D WHT 1A inz(x'22') D WHT_RI 1A inz(x'23') D GRN_UL 1A inz(x'24') D GRN_UL_RI 1A inz(x'25') D WHT_UL 1A inz(x'26') D ND 1A inz(x'27') D RED 1A inz(x'28') D RED_RI 1A inz(x'29') D RED_HI 1A inz(x'2A') D RED_HI_RI 1A inz(x'2B') D RED_UL 1A inz(x'2C') D RED_UL_RI 1A inz(x'2D') D RED_UL_BL 1A inz(x'2E') D TRQ_CS 1A inz(x'30') D TRQ_CS_RI 1A inz(x'31') D YLW_CS 1A inz(x'32') D WHT_RI_CS 1A inz(x'33') D TRQ_UL_CS 1A inz(x'34') D TRQ_UL_RI_CS 1A inz(x'35') D YLW_UL_CS 1A inz(x'36') D PNK 1A inz(x'38') D PNK_RI 1A inz(x'39') D BLU 1A inz(x'3A') D BLU_RI 1A inz(x'3B') D PNK_UL 1A inz(x'3C') D PNK_UL_RI 1A inz(x'3D') D BLU_UL 1A inz(x'3E') * Fields will be protected D PR_GRN 1A inz(x'A0') D PR_GRN_RI 1A inz(x'A1') D PR_WHT 1A inz(x'A2') D PR_WHT_RI 1A inz(x'A3') D PR_GRN_UL 1A inz(x'A4') D PR_GRN_UL_RI 1A inz(x'A5') D PR_WHT_UL 1A inz(x'A6') D PR_ND 1A inz(x'A7') D PR_RED 1A inz(x'A8') D PR_RED_RI 1A inz(x'A9') D PR_RED_HI 1A inz(x'AA') D PR_RED_HI_RI 1A inz(x'AB') D PR_RED_UL 1A inz(x'AC') D PR_RED_UL_RI 1A inz(x'AD') D PR_RED_UL_BL 1A inz(x'AE') D PR_TRQ_CS 1A inz(x'B0') D PR_TRQ_CS_RI 1A inz(x'B1') D PR_YLW_CS 1A inz(x'B2') D PR_WHT_RI_CS 1A inz(x'B3') D PR_TRQ_UL_CS 1A inz(x'B4') D PR_TRQ_UL_RI_CS 1A inz(x'B5') D PR_YLW_UL_CS 1A inz(x'B6') D PR_PNK 1A inz(x'B8') D PR_PNK_RI 1A inz(x'B9') D PR_BLU 1A inz(x'BA') D PR_BLU_RI 1A inz(x'BB') D PR_PNK_UL 1A inz(x'BC') D PR_PNK_UL_RI 1A inz(x'BD') D PR_BLU_UL 1A inz(x'BE') |
I know the subfield names are not great, but I think they are descriptive once you work out that they are the color codes followed by the display attribute codes.
I would keep this data structure in its own member, that way it can be copied into the source code of another.
I have also qualified the data structure, therefore, when using any of the subfields I have to qualify it with the data structure's name. For example to change the attribute to red and reverse image I would code the subfield as: PgmToSys.RED_RI
This means I can do the same as my previous example of RPGLE/RPG IV code as:
01 FDISPLAYF CF E WORKSTN 02 /include mylib/mysrc,pgm2sysfld 03 /free 04 PFLD001 = PgmToSys.RED_RI ; 05 exfmt SCREEN1 ; |
On line 2 I have used /INCLUDE, which is the same as /COPY. PGM2SYSFLD is the name of the member that contains the data structure.
You can learn more this on the IBM website:
This article was written for IBM i 7.1, and it should work with earlier releases too.
Excellent, thanks for posting this.
ReplyDeleteThanks for sharing this. Wish I had known about this 15 or 20 years ago.
ReplyDeletePretty slick!!
ReplyDeleteI remember doing this on 34/36 with biton bitof and placing the single byte characters either end of the data to do the same - much easier these days - nice article.
ReplyDeleteThis is good. I've been using this technique since 2006.
ReplyDeleteNice article.
ReplyDeleteThanks,
Simon
Excellent Simon
ReplyDeleteBy using the %bitor BIF the set of constants can be must shorter:
ReplyDelete-- Constants
d cDspBlue c Const(x'3A')
d cDspGreen c Const(x'20')
d cDspPink c Const(x'38')
d cDspRed c Const(x'28')
d cDspTurquoise c Const(x'30')
d cDspWhite c Const(x'22')
d cDspYellow c Const(x'32')
d cDspNormal c Const(x'20')
d cDspProtect c Const(x'80')
d cDspColSep c Const(x'10')
d cDspBlink c Const(x'08')
d cDspUnderline c Const(x'04')
d cDspHilite c Const(x'02')
d cDspReverse c Const(x'01')
d cDspNonDisplay c Const(x'07')
-- Function
//--------------------------------------------------------------------
p SetDdsProperties...
p b
d pi 1a
d @color 1a
d @protect n
d @error n
// Workfields
d @ddsProperty s 1a
/free
@ddsProperty = cDspGreen;
if @protect;
@ddsProperty = %bitOr(@ddsProperty:cDspProtect);
else;
@ddsProperty = %bitOr(@ddsProperty:cDspUnderline);
endif;
if @error;
@ddsProperty = %bitOr(@ddsProperty:cDspReverse);
endif;
return @ddsProperty;
/end-free
p e
-- Usage
-- Protect/Read only/Output
PFLD001 = SetDdsProperties(cDspGreen:*On:*Off);
-- Error
PFLD001 = SetDdsProperties(cDspGreen:*Off:*On);
and de Position Cursor? I already knew this trick, but still had to use dspatr(pc).
ReplyDeletebtw: %bitxx i don't like.... It reminds me of old pgms. I try avoid it
Write a function around API QDFRTVFD (DSPFFD) to retrieve the position of the field and set it via DDS keyword CSRLOC.
ReplyDeleteI made a SRVPGM to do all of this, works like a charm. No more counting indicators, reorganizing datastructures....
As a hint I will give the function names I have used, take your time to build your own and test it, but it will pay itself back:
SCREEN_Init (Register the given screen/format for all fields and field attributes via QDFRTVFD)
SCREEN_Finale (UnRegister the given screen/format)
SCREEN_ErrorFlags (Set all error flags on or off)
SCREEN_ProtectFlags (Set all protect flags on or off)
SCREEN_HiddenFlags (Set all hidden flags on or off)
SCREEN_Field (Set current field)
SCREEN_Error (Set the error flag on for current field)
SCREEN_Protect (Set the protect flag on for current field)
SCREEN_Hidden (Set the error flag on for current field)
SCREEN_Color (Set the color for the current field
SCREEN_GetDdsProp (Get the value for the Program To Display Field for the given fieldname)
SCREEN_CursorTo (Get the position of the given field)
SCREEN_CursorToFirstError (Get the position of the first field in error)
SCREEN_FormatToFirstError (Get the formatname where the first field in error is on)
SCREEN_IsError (Is the given field in error or, when no parameter, is there any field in error)
(As I use a SRVPGM all functions work with a handle (return of SCREEN_Init) to support multiple screen and formats)
One small caveat with using DSPATR with a program-to-system field: In the unlikely event that you still have black-and-white (or black-and-green) 5250 workstations, your program will need to test the display model and set the attribute field appropriately for both monochrome and color displays. DDS normally does this for you, with the COLOR keyword overriding the DSPATR(HI BL CS) attributes, but only on color displays.
ReplyDeleteProbably 99% of System i shops are color-only, so this caveat only applies to the remaining 1% or so that still have some monochrome displays around.
Not also having a value that initially and then conditionally positions the display's cursor may be a real drawback that holds folk back from using the technique.
ReplyDeletePlus the above remark about OVERLAY makes a valid point.
Instead of having massive conditioned 'dirty' display formats, a set of clean formats containing only relevant data items ultimately easier and safer. Also makes sense for print formats too.
Definitely something to keep for future use and reference -
ReplyDeleteThanks for your effort.
Thanks for the sharing. It clears my question at great deal.
ReplyDeleteI used Program-to-system field for a regular screen. Can this be used for WINDOWS in a DSPF? Or do you need indicators to see your errors?
ReplyDelete