I decided to write the post after being asked if I had an example of having two subfiles on the same screen. I did a quick search using Google and was unable to find what I considered a good example I felt comfortable sharing.
In this example I am going to show two subfiles horizontally (i.e. one on top of the other). I could have shown them vertically (next to one another), or even had more than two. The principals I show here can easily be adapted to fit either of those other scenarios. The most important thing to remember is that each set of subfile and subfile control record format cannot overlap another.
To reduce the size of the display file source code, shown here, I have removed all unnecessary color and display attributes codes that I use in the screens I build. I am going to show my display source in multiple parts to make it easier to understand what each record format is for. Let me start with the file level keywords.
01 A DSPSIZ(24 80 *DS3) 02 A PRINT 03 A ERRSFL 04 A INDARA 05 A CA03(03 'F3=Exit') |
Those of you familiar with my posts will recognize the following keywords:
Line 3: I always use the error subfile. The display file controls it without any extra programming.
Line 4: By using the indicator area I can give the display file indicators meaningful names in my RPG program rather than use the number.
The examples I did find for more than one subfile on a screen, put the page headings in a separate record format. In my example I am going to include them in the subfile control record format, CTL01, for the first subfile, SFL01.
06 A R SFL01 SFL 07 A Z1RRN 5S 0H 08 A Z1LINE 50A O 5 3 |
The subfile record format for the first subfile with just two fields.
- Z1RRN: The subfile record number
- Z1LINE: A field of 50 characters
The subfile control record for the first subfile, CTL01, might look complicated. Rest assured it is not, most of the code is for the screen headings.
09 A R CTL01 SFLCTL(SFL01) 10 A SFLSIZ(0030) 11 A SFLPAG(0006) 12 A OVERLAY 13 A 31 SFLDSP 14 A 30 SFLDSPCTL 15 A N30 SFLDLT 16 A 30 SFLEND(*MORE) 17 A 1 2USER 18 A 1 31'R P G P G M . C O M' 19 A 1 63TIME 20 A 1 72DATE 21 A EDTCDE(Y) 22 A Z1SCREEN 12A O 2 2 23 A 2 26'Example screen with 2 + subfiles' 24 A 2 72SYSNAME 25 A 3 2' - 26 A - 27 A ' 28 A DSPATR(UL) 29 A 4 36'SUBFILE 1' |
Lines 10 and 11: This is a small load all subfile of 30 records (line 10), with only six displaying on the screen at one time (line 11).
Lines 13 – 16: I am using indicators 30 and 31 to condition the display of SFL01.
Lines 17 – 29: The rest of the this record format is for the screen headings.
The second subfile is just about the same as the first.
30 A R SFL02 SFL 31 A Z2RRN 5S 0H 32 A Z2LINE 50A O 15 3 |
The subfile control record format, CTL02, is very simple:
33 A R CTL02 SFLCTL(SFL02) 34 A SFLSIZ(0030) 35 A SFLPAG(0006) 36 A OVERLAY 37 A 33 SFLDSP 38 A 32 SFLDSPCTL 39 A N32 SFLDLT 40 A 32 SFLEND(*MORE) 41 A 13 2' - 42 A - 43 A ' 44 A DSPATR(UL) 45 A 14 36'SUBFILE 2' |
Lines 33 and 34: This subfile, like the first, is a load all subfile of 30 rows, and displays six at a time.
Lines 37 – 40: I could have used the same indication to display the subfile control as I did for SFL01, but I decided that this subfile deserves its own indicators.
The last record format of the display file is the footer section, which I use to display the available function keys.
46 A R FOOTER 47 A 23 3'F3=Exit' |
The RPG program to display these two subfiles is also simple.
01 **free 02 ctl-opt option(*nodebugio:*srcstmt) dftactgrp(*no) ; 03 dcl-ds Pgm extname('RPG4DS') psds qualified 04 end-ds ; 05 dcl-f TESTDSPF workstn indds(Dspf) 06 sfile(SFL01:Z1RRN) sfile(SFL02:Z2RRN) ; 07 dcl-ds Dspf qualified ; 08 Exit ind pos(3) ; 09 Sfl1DspCtl ind pos(30) ; 10 Sfl1Dsp ind pos(31) ; 11 Sfl2DspCtl ind pos(32) ; 12 Sfl2Dsp ind pos(33) ; 13 end-ds ; 14 Z1SCREEN = %trimr(Pgm.ProcNme) + '-1' ; 15 LoadSubfiles() ; 16 dow (1 = 1) ; 17 write FOOTER ; 18 write CTL01 ; 19 exfmt CTL02 ; 20 if (Dspf.Exit) ; 21 leave ; 22 endif ; 23 enddo ; 24 *inlr = *on ; |
Line 1: Yes, this program is in all free RPG.
Line 2: My favorite control options, and I need to give the DFTACTGRP(*NO) as I am using a procedure in this program.
Lines 3 and 4: I want to display the program's name on the screen, which I will get from the program data structure. I have mine externally defined to make it easier to include into many different programs.
Lines 5 and 6: This is the definition of my display file. The INDDS is the other part off DDS's INDARA and gives the name of the indicator data structure. Line 6 contains the definitions for the subfiles. As I have more than one subfile that I will use I need to give each one its own SFILE.
Lines 7 – 13: Having just mentioned the indicator data structure here it is. Here I define variable names that I will be using instead of the indicator numbers. As I have defined the data structure with QUALIFIED the subfields will need to be qualified with the data structure's names.
Line 14: I am making the screen name from the program name retrieved from the program data structure.
Line 15: In this procedure the subfiles are loaded. I will show its content below.
Lines 16 – 23: Within this Do loop the screen is displayed.
Lines 17 – 19: These are the record formats being written to the screen. The footer record needs to be first. It does not matter whether CTL01 is written first or CTL02 is, providing the second control record format is EXFMT.
17 write FOOTER ; 18 write CTL02 ; 19 exfmt CTL01 ; |
Lines 20 – 22: If the F3 key has been pressed I leave the Do loop.
The procedure to load the subfiles is a breeze.
25 dcl-proc LoadSubfiles ; 26 dcl-c MaxSfl 30 ; // Maximum records in subfile 27 Dspf.Sfl1DspCtl = *off ; 28 Dspf.Sfl1Dsp = *off ; 29 write CTL01 ; 30 Dspf.Sfl1DspCtl = *on ; 31 Dspf.Sfl1Dsp = *on ; 32 for Z1RRN = 1 to MaxSfl ; 33 Z1LINE = 'Subfile No. 1 Record ' + %char(Z1RRN) ; 34 write SFL01 ; 35 endfor ; 36 Dspf.Sfl2DspCtl = *off ; 37 Dspf.Sfl2Dsp = *off ; 38 write CTL02 ; 39 Dspf.Sfl2DspCtl = *on ; 40 Dspf.Sfl2Dsp = *on ; 41 for Z2RRN = 1 to MaxSfl ; 42 Z2LINE = 'Subfile No. 2 Record ' + %char(Z2RRN) ; 43 write SFL02 ; 44 endfor ; 45 end-proc ; |
Line 26: I defined a constant to contain the maximum number of records in the subfiles.
Lines 27 – 31: Initializing the subfile SFL01 and setting on the indicators to display it.
lines 32 – 35: This For group is used to load SFL01. I am just writing a string to each subfile record until the maximum is reached.
Lines 36 – 40: Initializing SFL02 as I did for SFL01.
Lines 41 – 44: Loading SFL02 in the same manner I did the other subfile.
When the program is compiled and run I am presented with this screen:
SIMON R P G P G M . C O M TT:TT:TT DD/DD/DD TESTPGM-1 Example screen with 2 subfiles DEV730 ______________________________________________________________________________ SUBFILE 1 Subfile No. 1 Record 1 Subfile No. 1 Record 2 Subfile No. 1 Record 3 Subfile No. 1 Record 4 Subfile No. 1 Record 5 Subfile No. 1 Record 6 More... ______________________________________________________________________________ SUBFILE 2 Subfile No. 2 Record 1 Subfile No. 2 Record 2 Subfile No. 2 Record 3 Subfile No. 2 Record 4 Subfile No. 2 Record 5 Subfile No. 2 Record 6 More... F3=Exit |
I can position the cursor to either subfile and Page Up or Down to my heart's content.
I like the More... and Bottom. Others do not when they are using subfiles of a limited size like in this example, preferring the "+" to indicate there are more subfile records.
If I change to use the + I can also add a seventh record to be displayed. The changes to the display would be.
11 A SFLPAG(0007) 16 A 30 SFLEND 35 A SFLPAG(0007) 40 A 32 SFLEND |
And the screen would look like this:
SIMON R P G P G M . C O M TT:TT:TT DD/DD/DD TESTPGM-1 Example screen with 2 subfiles DEV730 ______________________________________________________________________________ SUBFILE 1 Subfile No. 1 Record 1 Subfile No. 1 Record 2 Subfile No. 1 Record 3 Subfile No. 1 Record 4 Subfile No. 1 Record 5 Subfile No. 1 Record 6 Subfile No. 1 Record 7 + ______________________________________________________________________________ SUBFILE 2 Subfile No. 2 Record 1 Subfile No. 2 Record 2 Subfile No. 2 Record 3 Subfile No. 2 Record 4 Subfile No. 2 Record 5 Subfile No. 2 Record 6 Subfile No. 2 Record 7 + F3=Exit |
Having more than one subfile on a screen can be very useful for displaying information to users, and, as you have seen, is not difficult to code.
This article was written for IBM i 7.3, and should work for earlier releases too.
Good exercise in controlling 2 subfiles.
ReplyDeleteif not mistaken we can display max 4 subfiles...
DeletePet peeve... why not "dow (Dspf.Exit = *off)" instead of "dow (1 = 1)"? Shorter and clearer, especially if the program grows more complicated. Alternatively "dou" if it's a matter of top vs. bottom testing.
ReplyDeleteExcellent
ReplyDeleteI prefer DoU ( %ShtDn ) ;
ReplyDeleteAnd you can use the SFLSCROLL /SFLRCDNBR RRN in each subfile DDS to keep the subfiles on their current page if user hits ENTER.
Ringer
For those who do not know: How to use SFLRCNBR
DeleteI did simething like this before and it was working, but my design was not approved since it did not meet any of the company standard
ReplyDeleteSometimes we need to be pioneers and show others what is possible.
DeleteAny company whose standards do not evolve with end up with dinosaurs programming for them.
Pgm extname('RPG4DS') --> what are fields in this file, mister ?
ReplyDeleteThere is a link in the sentence that describes that RPG4DS is the program data structure to a post that describes and lists all the subfields for this data structure.
DeleteThanks, Simon. I'm writing an app that makes a call to a certain number of other programs and shows the values of the output parms. Using your method, I'll gather the input parms up top and the output parms on the bottom after validation. That's my proposal anyway. I was asked just to create a pgm and screen per module but creating a table to house the name of the modules and their parms seems much more elegant.
ReplyDelete