RPGサイクルとともに驚くほどサブファイル(SFL
) の使用方法についての誤解が多いので、あえて
ここで改めて解説する。
SFL
は明細行の表示画面を作成するに当たって、これほどやさしくて便利な機能は無い。
しかし多くの誤解のために SFL
を正しく扱われていない場合も多い。
まず、SFL
とは何であろうか?
多くのスクロール可能な明細行を大量に表示したい場合、SFL
は次のような機能を提供する。
SFL
はメモリ上に多くの行数のレコードを表示するが、実際にユーザーの目に見えているのは
サブ・ファイル・ページ数として定義された行数のみである。
このような状態となった SFL
は
ユーザーがロール・アップ/ダウンキーを押しても OS400が制御して画面上の表示のスクロールを行い、ユーザー・プログラムに制御は渡らない
つまり一旦、サブファイルが表示されてしまうとユーザー・プログラムはスクロールのための制御を記述する必要がないのである。
制御を行う必要がないとユーザー・プログラムは今、ユーザーがどの辺りを眺めているのか
知ることができないように思えるが、これは心配する必要がない。
これについては後述する。
ユーザー・プログラムに制御が渡るのは操作員がサブファイル・ページを超過してさらにロール・アップ要求を行った場合のみである
つまり最初にすべてのデータをサブファイルに書き込んでしまってから操作員に制御を渡すのではなく、ロールアップ要求があったときのみに、次に表示すべき画面のサブファイル・
レコードを書き出すようにすれば良いのである。
例えばプラウザ上での検索エンジンによる検索を想像してみて欲しい。
検索して見つかったサイトが 1200件見つかったものとしても、検索エンジンは最初の10行
程度しか表示しないはずである。
SFL
もこれと同じで最初のページだけを表示するようにするだけで十分である。
SFLSIZ を SFLPAG の +1だけ大きく定義しておくと SFL は自動拡張される。
SFL
を表示レコードをすべて収容できるだけのサイズを予め指定しておく必要はない。
SFLPAG(17) のように SFLSIZ
数を SFLPAG数 + 1
にしておくだけでOS400 に
よって自動拡張される。
サブ・ファイルの誤解
@サブ・ファイルはパフォーマンスが悪い ?
SFL
の自動拡張機能を知らずに SFL
には最初から該当レコードをすべて埋め込む必要が
あると考えて、最初にすべての該当レコードを SFL
に書き出すような記述をすると、当然の
ことながら、該当レコードが例えば 10000件あれば SFL
が表示されるまでに時間がかかって
しまう。
SFL
には最初の表示ページ数のレコード件数だけ書き出せばさっさと表示してしまうだけで
十分なのである。
次に操作員が次頁を要求したときに初めて次のレコードを読めばよい。
SFL
はその時点で自動拡張されるのである。
ASFLSIZ
= SFLPAG
として定義してしまう。
これでは自動拡張もされずに SFL
を使うメリットが無くなってしまう。
SFLSIZ
= SFLPAG
としてしまう誤解の背景には、スクロール中にユーザー・プログラムに
制御が渡らないのでカーソル位置などによるレコードの取得ができないのではないかと思い
込んでいるせいである。
OS400 の SFL
は実に良く考慮されていて例外処理のために SFL
の使用が不便になる
ことはまず無い。
BSFL
の記述は複雑になる ?
SFL
を使って処理の記述がもし複雑になっているとしたら、それはどこかに SFL
の使用方法
に大きな誤解が潜んでいると思って間違いないであろう。
SFL
の使用に特殊なテクニックは必要ない。
むしろ SFL
を使ったほうが処理は非常に単純なものとなるはずである。
CWRITE
したばかりの SFL
に CHAIN/UPDATE
する ?
これも多い誤解の使用方法で、LOOP文で WRITE SFL
した後で再び LOOP させて SFL
に CHAIN
して UPDATE
を行う処理も多い誤解のひとつである。
もし、このような複雑な処理を記述していたとしたら SFL
が理解されてないことになる。
SFL
は記述を単純にするために考慮されたもので、複雑なテクニックをもし使用していたとしたら、
それは SFL
の使用方法を誤っていることになる。
サブファイルの作り方
サブファイルの作成は実に簡単である。
@SFLCLR
によってサブファイルを初期クリヤーする。
最初に SFLCLR
を入れない開発者もいるが、行儀の良いPGM のために必ず最初に
SFLCLR
を実行させるようにする。
Aレコードを読んでサブファイルにレコードを追加する。
該当レコードを読んで SFLPAG
の文だけ LOOP してレコードを WRITE SFL
にして追加する。
Bロールアップ・キーが押されたら再びAの処理で SFL
へ追加する。
たった、これだけのことである。
ロールダウン・キーが押されたときの処理は記述する必要はない。
サブファイルの特殊なテクニック
@変更のあったレコードだけを読む READC
READC ( READ CHANGE)
命令を使用するとユーザーが何らかの手を加えた行だけを読み
取ることができる。
例えばある 100として表示されている項目を操作員が 120 と変更するとその行だけが
READC
によって読み取られるのはもちろんであるが、100という数字を同じ 100に変更した
場合でも READC
には読み取ることができるのである。
これは SFL
でないとできないことはないが配列型であれば複雑な処理が必要である。
DO READC SFL 50 50 LEAVE (変更レコードだけの処理をここに入れる) END
A今、処理しているサブファイル・レコードの RRN (レコード番号) を調べる
サブファイルを使用している DSPF
に INFDS
を定義して INFDS
から取得することができる。
FANS004FM CF E WORKSTN F SFILE(SFREC01:RRN1) F INFDS(INFDS) : D INFDS DS D LINE 370 371B 0 D TOPRRN 378 379B 0 D BRRN 376 377B 0
のように記述するものとする。
このうち SFL
に対して入/出力を行うと、 BRRN には今、入/出力を行った直後に
そのサブファイル・レコードの RRN が更新されている。
例えば READC を行った直後には BRRN にはそのレコードのRRN が保管されている。
B カーソルの位置からサブファイル・レコードを特定する
操作員がサブファイルの特定の行にカーソルを位置づけてある機能キーを押してプロンプト要求
などを試みたときに、カーソルが位置づけられたのは、どのレコードであるかを特定することが
できる。
前述のAの INFDS
を見て欲しい。
INFDS
のうち、TOPRRN
とは今、現在表示されているサブファイルの先頭の SFL
レコードの
RRN
が保管されている。
サブファイル全体を操作員がどのようにスクロールしても制御がプログラムに戻ったときには最後に
表示されているサブファイルの先頭のRRN
が入っている。
これを取得することによって、どのようなサブファイルであっても、どのあたりに位置されているかを
特定することができる。これによって SFLSIZ
= SFLPAG
に設定する必要が無いことはお分かり
頂けるものと思う。
次に INFDS
の LINE
にはカーソルの位置が保管されている。
そこで、
LINE DIV 256 LIN 3 0 <--- カーソル行番号 MVR POS 3 0 <--- カーソル桁番号
によってカーソルが位置づけられた行と桁を算出することができる。
サブファイル・レコードの開始行(表示行) を STRGYO
とすると
LIN SUB STRGYO RRN1 ADD TOPRRN RRN1
この RRN1
が求める「操作員がカーソルを位置づけた SFL レコードの RRN」である。
そこで、
RRN1 CHAIN SFREC01 90
によって求める SFL
レコードを取り出すことができる。
以上のようにサブファイルの処理は何も難しい処理は無い。
もしサブファイルに特殊なロジックを入れているとすると必ずそれはサブファイルを誤解して使用して
いるものと判断して、ほぼ間違いない。
サブファイルは処理をやさしくするための機能であって、決して複雑にするための機能ではないのだ。
クリヤーしてからレコードを追加する。ただこれだけのことである。