【環境】
Delphi 10.2.2
FastReport 5
やりたいこと
- ヘッダーグループ毎に改ページを行う
- 明細行は3行固定、2行以下の場合空白行を挿入したい
- 明細行が4行以上の場合も改ページ必要
- 1ページに4項目、同一のヘッダー情報、明細情報を繰り返す(最小限のコードで保守を楽にしたい)
やりたい表示処理
ヘッダー(1項目)
明細1
明細2 or 空白行
明細3 or 空白行
フッター
ヘッダー(2項目)
明細1
明細2 or 空白行
明細3 or 空白行
フッター
ヘッダー(3項目)
明細1
明細2 or 空白行
明細3 or 空白行
フッター
ヘッダー(4項目)
明細1
明細2 or 空白行
明細3 or 空白行
フッター
成果物サンプル

フロー
-
DB準備、加工
- TFDQuery クエリエディタ作成
- TCliendDataSet フィールドセット
- TfrxDBDataset 更新
-
fastReport作成
- fastReport データ連携
- fastReport Page作成
- fastReport Code作成
- fastReoprt イベント連携
DB
加工前
加工後
順序的に明細加工から作成します。
明細加工SQL文
select DENSE_RANK() OVER(ORDER BY T.OldMTNO) AS キーNo,
T.NewGNO AS MAX3行,T.MTGNO AS 明細No, T.MHNO AS 見積No,MTSHNM AS 品名
FROM
(select --3行明細のため%3している
(case when (MTGNO > 3) and (MTGNO % 3 = 0) then (RANK() OVER(ORDER BY MHIRDT,MHTKCD))+(MTGNO/3-1)
else
(case when (MTGNO > 3) and (MTGNO % 3 = 2) then (RANK() OVER(ORDER BY MHIRDT,MHTKCD))+(MTGNO/3)
else
(case when (MTGNO > 3) and (MTGNO % 3 = 1) then (RANK() OVER(ORDER BY MHIRDT,MHTKCD))+(MTGNO/3)
else
(RANK() OVER(ORDER BY MHIRDT,MHTKCD)) end)end)end) AS OldMTNO,
(case when (MTGNO % 3 = 1) then 1
else
(case when (MTGNO % 3 = 2) then 2
else
(case when (MTGNO % 3 = 0) then 3
else
0 end) end) end) as NewGNO,
MH.*,
MM.*
from MTMFLP AS MM
LEFT JOIN MTHFLP AS MH
ON MM.MTNO = MH.MHNO) AS T
WHERE 1=1
--and T.MHTKCD in ('002','003','004') //最初は数件で試した方がよい
ORDER BY T.MHNO,T.MTGNO --ユニークになるように
ヘッダー加工SQL文
SELECT DENSE_RANK() OVER(ORDER BY T.OldMTNO) AS キーNo,
T.MHIRDT AS 見積日,T.MHNO AS 見積No,T.MHTKNM AS 得意先名
FROM
(SELECT --3行明細のため%3している
(case when (MTGNO > 3) and (MTGNO % 3 = 0) then (RANK() OVER(ORDER BY MHIRDT,MHTKCD))+(MTGNO/3-1)
else
(case when (MTGNO > 3) and (MTGNO % 3 = 2) then (RANK() OVER(ORDER BY MHIRDT,MHTKCD))+(MTGNO/3)
else
(case when (MTGNO > 3) and (MTGNO % 3 = 1) then (RANK() OVER(ORDER BY MHIRDT,MHTKCD))+(MTGNO/3)
else
(RANK() OVER(ORDER BY MHIRDT,MHTKCD)) end)end)end) AS OldMTNO,
(case when (MTGNO % 3 = 1) then 1
else
(case when (MTGNO % 3 = 2) then 2
else
(case when (MTGNO % 3 = 0) then 3
else
0 end) end) end) as NewGNO,
MH.*,
MM.*
from MTMFLP AS MM
LEFT JOIN MTHFLP AS MH
ON MM.MTNO = MH.MHNO) AS T
WHERE 1=1
--and T.MHTKCD in ('002','003','004') //最初は数件で試した方がよい
GROUP BY T.OldMTNO,T.MHIRDT,T.MHNO,T.MHTKNM
ORDER BY T.MHNO --ユニークになるように
TFDQuery(ヘッダー、明細)
各クエリエディタ作成で加工後のSQL文をセットする
TCliendDataSet(ヘッダー、明細)
フィールドをセットする
TfrxDBDataset(ヘッダー、明細)
フィールド更新する
fastReport
データ連携
コンポーネント展開>レポート>データ>(ヘッダー、明細)DBDataSetを選択
Page作成

グループヘッダー
- ヘッダー.キーNoをセット
- ヘッダー情報(見積№、納入年月日、得意先名など)が変われば改ページ
- 明細4行以降も改ページ
マスターデータ
- 明細をセット
ヘッダー
- 明細までの余白部分を設定
詳細データ
- 明細データセット割当
- フィルターにヘッダー.キーNo=明細.キーNoで連携させる
- 詳細データは1行分のため今回はheight*3が明細部分の高さになる
- イベントセットMasterData1OnBeforePrint
フッター
- 子バンドを挿入用の装置
- Height0
- イベントセット
- フッター1:Footer1OnBeforePrint
- フッター2:Footer2OnBeforePrint
子バンド
- 明細に空白行を挿入するための部分
- 詳細データと同じHeightに設定
- Child1は詳細データとフッターに設定している
オーバレイ
- ヘッダーフィールドはオーバレイ部分にセット
- ※オーバレイ作成時※ミシン目位置を最初に決める
再調整はかなり面倒です※
Code作成
fastReport Code
var
PageLine: integer;//現在の行数を出力します
PageMaxRow: integer =3;//ページあたりの最大行数を設定します
procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
begin
PageLine := <line> mod PageMaxRow; //このコードは固定数の行に必要です
child1.visible := False; //初期化
child2.visible := False; //初期化
end;
//1,3,4項目用 フッターイベント
procedure Footer1OnBeforePrint(Sender: TfrxComponent);
var
i: integer;
begin
i := IIF(PageLine = 0, PageMaxRow, PageLine);
child1.visible := True;
while i < PageMaxRow do
begin
i := i + 1;
Engine.ShowBand(Child1);//空白のフォームを印刷する
end;
child1.visible := False;//初期化
end;
//2項目専用 フッターイベント
procedure Footer2OnBeforePrint(Sender: TfrxComponent);
var
i: integer;
begin
i := IIF(PageLine = 0, PageMaxRow, PageLine);
child2.visible := True;
while i < PageMaxRow do
begin
i := i + 1;
Engine.ShowBand(Child2);//空白のフォームを印刷する
end;
child2.visible := False;//初期化
end;
begin
end.
イベント連携
各詳細データ: MasterData1OnBeforePrint
フッター1:Footer1OnBeforePrint
フッター2:Footer2OnBeforePrint
Pageから各バンドプロパティに設定する
苦労した点
明細行数を1,2,3-1,2,3と繰り返す部分
改ページ対応のためNewMTNOをセットする部分
一気にやろうとせずにステップごとに試行して組み合わせていった