|
Delphi Programming / Object Pascal
[掲載 2000年12月12日] [更新 2016年04月19日] 印刷プレビュー制御コンポーネント |
印刷プレビュー制御コンポーネント
テストプログラム QueryPrint |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
クエリーの結果を印刷 ( 先読み方式・逐次表示方式 ) |
エリーの結果を表形式で印刷する例です.プログラムは,表の罫線を引くルーチンと実際のデータを印刷するルーチンに分けて,1 行の行高さから印刷行数を計算し,そこから必要な頁数も計算する方法を使用しています.また,BLOB 型データの印刷例も示しました.プログラムは 3 つですが,プレビューフォーム,印刷プレビューコンポーネントとも 1 つを兼用しています.
実行には,Delphi に付属の DBDEMOS というデータベースが必要です. |
[備考]
このテストプログラムは,BDE 経由で Paradox のデータを扱っています.DBDEMOS は Paradox データベースのエイリアス名です.
|
|
図1
設計時の画面
|
|
図2
表形式の実行結果 |
|
図3
画像とメモ項目の実行結果 |
リスト1
メインフォームのコード.作成した描画用のメソッドを呼出す方式 |
unit QueryPrintUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons, plPrev;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
StaticText1: TStaticText;
plPrev1: TplPrev;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
Unit1,
Unit2,
Unit3;
{$R *.DFM}
//=============================================================================
// 先読み方式で表の印刷
// Unit1のQPrint1というクラスのPrintContメソッドを実行
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
QPrint1.PrintCont;
end;
//=============================================================================
// 逐次表示方式で表の印刷
// Unit2のQPrint2というクラスのPrintStatメソッドを実行
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
QPrint2.PrintStat;
end;
//=============================================================================
// BLOB型データの印刷
// Unit3のQPrint2というクラスのPrintBlobメソッドを実行
// 描画開始まで少し時間がかかる
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
begin
QPrint3.PrintBlob;
end;
end.
リスト2
Unit1 のコード.表形式でデータ表示 (先読み方式) |
unit Unit1;
interface
type
TQPrint1 = class
private
procedure PageKeisen(Yt, Yb, RowCnt: Integer);
function GetRowCnt(Yt, Yb: Integer): Integer;
procedure PrintOnePage(Yt, Yb, RowCnt: Integer);
public
procedure PrintCont;
end;
var
QPrint1: TQPrint1;
implementation
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Math, DM1Unit, plPrev, QueryPrintUnit;
// 共通変数
// 見やすいようにここに書いているが実際にはprivate,public部がいいだろう
var
FStartPosY1 : Integer; //1頁目の表上端
FStartPosY2 : Integer; //2頁目以降の表上端
FEndPosY : Integer; //表下端の下限値
FRowHeight : Integer; //行高
FRowCount1 : Integer; //1頁目の行数
FRowCount2 : Integer; //2頁以降の行数
FVKeisenPos : array[0..5] of Integer; //縦罫線の位置
FplPrev : TplPrev; //印刷プレビュー制御コンポ
//-----------------------------------------------------------------------------
// 先読み方式による描画ルーチン
//
// 行の高さを決めれば1頁に印刷可能な行数が決まる(行数を決定してから行高さを
// 決定する場合も考えられる.あるいは指定の形式の場合は行高さも行数も決められ
// ていることもある).
// ここではA4縦(210.0mm,297.0mmと仮定)で行高さを10.0mmとし,1頁目はタイトル
// の印刷分を空けるものとする.
//
// (用紙の下に印刷余裕が無くなったら改頁する方法もある)
//-----------------------------------------------------------------------------
procedure TQPrint1.PrintCont;
begin
//plPrevはForm1のplPrev1を使用
FplPrev := Form1.plPrev1;
FVKeisenPos[0] := 150;
FVKeisenPos[1] := 320;
FVkeisenPos[2] := 920;
FVkeisenPos[3] := 1090;
FVkeisenPos[4] := 1670;
FVkeisenPos[5] := 1970;
FStartPosY1 := 500;
FStartPosY2 := 300;
FEndPosY := 2700;
FRowHeight := 100;
with DM1.Query1 do begin
Close;
SQL.Clear;
SQL.Add('select CustNo, Company, Zip, Addr1, Phone from customer');
Open;
end;
//1頁目の印刷可能行数
FRowCount1 := GetRowCnt(FStartPosY1, FEndPosY);
//2頁目以降の印刷可能行数
FRowCount2 := GetRowCnt(FStartPosY2, FEndPosY);
FplPrev.Title := '表の印刷例';
FplPrev.BeginDoc;
try
while True do begin
//1頁目と2頁目以降では罫線描画開始位置と行数が異なるので別々
if FplPrev.PageNumber = 1 then begin
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(80);
FplPrev.TextRectJust(FVKeisenPos[0] + 500,
FVKeisenPos[5] - 500,
250,
400,
'表の印刷例');
//1頁分のデータを描画
PrintOnePage(FStartPosY1, FEndPosY, FRowCount1);
//罫線を描画
PageKeisen(FStartPosY1, FEndPosY, FRowCount1);
end else begin
//1頁分のデータを描画
PrintOnePage(FStartPosY2, FEndPosY, FRowCount2);
//罫線を描画
PageKeisen(FStartPosY2, FEndPosY, FRowCount2);
end;
//データが無ければ終了
if DM1.Query1.Eof then break;
FplPrev.NewPage;
end;
finally
FplPrev.EndDoc;
end;
//Showで表示してしまうと次行でクエリーが閉じてしまう
FplPrev.ShowModal;
DM1.Query1.Close;
end;
//-----------------------------------------------------------------------------
// 表の罫線部分と印刷日時を印刷
//
// 共通部分と考えられる表の罫線と印刷日時を印刷するルーチン.
// つまり書類の背景と言える部分のコード.
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
// RowCnt 行数.1頁と2頁以降では異なる
//-----------------------------------------------------------------------------
procedure TQPrint1.PageKeisen(Yt, Yb, RowCnt: Integer);
var
LPosY : Integer;
LBottom : Integer;
LLeft : Integer;
LRight : Integer;
LDateStr : String;
LRowNo : Integer;
LColNo : Integer;
begin
FplPrev.LineWidth(1);
FplPrev.LineStyle(psDot);
LLeft := FVKeisenPos[0];
LRight := FVKeisenPos[Length(FVKeisenPos) - 1];
FplPrev.LineWidth(1);
//横罫線はタイトル行も含めるので+1
for LRowNo := 1 to RowCnt + 1 do begin
LPosY := Yt + (LRowNo - 1) * FRowHeight;
FplPrev.Line(LLeft, LRight, LPosY, LPosY);
end;
//縦罫線の一番下のY座標値
LBottom := Yt + RowCnt * FRowHeight;
//縦罫線の描画
for LColNo := 0 to Length(FVKeisenPos) - 1 do begin
FplPrev.Line(FVKeisenPos[LColNo], FVKeisenPos[LColNo], Yt, LBottom);
end;
//印刷日時を描画.書類は何時誰がが基本
LDateStr := '印刷日時 ' + FormatDateTime('yyyy/mm/dd hh:nn', Now);
FplPrev.FontName('MS 明朝');
FplPrev.FontSize(8);
FplPrev.TextOutRC(LRight, Yb + 50, LDateStr);
end;
//-----------------------------------------------------------------------------
// Y座標の上端,下端と行高さから描画可能な行数を算出
// 逐次表示方式と同じコード
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
//-----------------------------------------------------------------------------
function TQPrint1.GetRowCnt(Yt, Yb: Integer): Integer;
begin
Result := Trunc((Yb - Yt) / FRowHeight);
end;
//-----------------------------------------------------------------------------
// 1頁分の印刷ルーチン 逐次表示方式と同じコード
// RowHの行高でRowCnt行分だけ描画する
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
//-----------------------------------------------------------------------------
procedure TQPrint1.PrintOnePage(Yt, Yb, RowCnt: Integer);
var
LX1 : Integer;
LX2 : Integer;
LY1 : Integer;
LY2 : Integer;
LText : String;
LRowNo : Integer;
LColNo : Integer;
begin
//タイトル行である1行目は色付きセルとする
FplPrev.BrushColor($00D9FFD9);
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(45);
FplPrev.FillRect(FVKeisenPos[0], FVKeisenPos[5], Yt, Yt + FRowHeight);
for LRowNo := 1 to RowCnt do begin
for LColNo := 0 to Length(FVKeisenPos) - 2 do begin
LX1 := FVKeisenPos[LColNo];
LX2 := FVKeisenPos[LColNo + 1];
LY1 := Yt + (LRowNo - 1) * FRowHeight;
LY2 := Yt + LRowNo * FRowHeight;
//タイトル行
if LRowNo = 1 then begin
FplPrev.TextRectCC(LX1, LX2, LY1, LY2, DM1.Query1.Fields[LColNo].FieldName);
end else begin
//データの描画
LText := '';
//データ項目値に応じて描画
case LColNo of
0:
begin //CustNo
LText := IntToStr(DM1.Query1.FieldByName('CustNo').AsInteger);
FplPrev.TextRectRC(LX1, LX2 - 15, LY1, LY2, LText);
end;
1: //Company
begin
LText := DM1.Query1.FieldByName('Company').AsString;
FplPrev.TextRectLC(LX1 + 15, LX2, LY1, LY2, LText);
end;
2: //Zip
begin
LText := DM1.Query1.FieldByName('Zip').AsString;
FplPrev.TextRectRC(LX1, LX2 - 12, LY1, LY2, LText);
end;
3: //Addr1
begin
LText := DM1.Query1.FieldByName('Addr1').AsString;
FplPrev.TextRectLC(LX1 + 15, LX2, LY1, LY2, LText);
end;
4: //Phone
begin
LText := DM1.Query1.FieldByName('Phone').AsString;
FplPrev.TextRectLC(LX1 + 15, LX2, LY1, LY2, LText);
end;
end;
end;
end;
//タイトル行でなければ次のデータ
if LRowNo > 1 then DM1.Query1.Next;
//データがなければ終了
if DM1.Query1.Eof then Break;
end;
end;
end.
リスト3
Unit2 のコード.表形式でデータ表示 (逐次表示方式) |
unit Unit2;
interface
type
TQPrint2 = class
private
procedure PrintRoutine;
procedure PageKeisen(Yt, Yb, RowCnt: Integer);
function GetRowCnt(Yt, Yb: Integer): Integer;
procedure PrintOnePage(Yt, Yb, RowCnt: Integer);
public
procedure PrintStat;
end;
var
QPrint2: TQPrint2;
implementation
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Math,DM1Unit, plPrev, QueryPrintUnit;
// 共通変数
// 見やすいようにここに書いているが実際にはprivate,public部がいいだろう
var
FStartPosY1 : Integer; //1頁目の表上端
FStartPosY2 : Integer; //2頁目以降の表上端
FEndPosY : Integer; //表下端の下限値
FRowHeight : Integer; //行高
FRowCount1 : Integer; //1頁目の行数
FRowCount2 : Integer; //2頁以降の行数
FRecordCount : Integer; //レコード数
FPageCount : Integer; //総頁数
FVKeisenPos : array[0..5] of Integer; //縦罫線の位置
FplPrev : TplPrev; //印刷プレビュー制御コンポ
//-----------------------------------------------------------------------------
// 各種の値を計算して実際の描画ルーチンを呼び出す
//
// 行の高さを決めれば1頁に印刷可能な行数が決まる(行数を決定してから行高さを
// 決定する場合も考えられる.あるいは指定の形式の場合は行高さも行数も決められ
// ていることもある).
// ここではA4縦(210.0mm,297.0mmと仮定)で行高さを10.0mmとし,1頁目はタイトル
// の印刷分を空けるものとする.
//-----------------------------------------------------------------------------
procedure TQPrint2.PrintStat;
begin
//plPrevはForm1のplPrev1を使用
FplPrev := Form1.plPrev1;
FVKeisenPos[0] := 150;
FVKeisenPos[1] := 320;
FVKeisenPos[2] := 920;
FVKeisenPos[3] := 1090;
FVKeisenPos[4] := 1670;
FVKeisenPos[5] := 1970;
FStartPosY1 := 500;
FStartPosY2 := 300;
FEndPosY := 2700;
FRowHeight := 100;
with DM1.Query1 do begin
SQL.Clear;
SQL.Add('select Count(CustNo) as RecCnt from customer ');
Open;
FRecordCount := DM1.Query1.FieldByName('RecCnt').AsInteger;
Close;
SQL.Clear;
SQL.Add('select CustNo, Company, Zip, Addr1, Phone from customer');
Open;
end;
//1頁目の印刷可能行数
FRowCount1 := GetRowCnt(FStartPosY1, FEndPosY);
//2頁目以降の印刷可能行数
FRowCount2 := GetRowCnt(FStartPosY2, FEndPosY);
//PageCntが総頁数.-1はタイトル行分.切上げ計算しないと頁数不足
FPageCount := Ceil(((FRecordCount) - (FRowCount1 - 1)) / (FRowCount2 - 1)) + 1;
FplPrev.Title := '表の印刷例';
FplPrev.PageCount := FPageCount;
FplPrev.ProcName := PrintRoutine;
//Showで表示してしまうと次行でクエリーが閉じてしまう
FplPrev.ShowModal;
DM1.Query1.Close;
end;
//-----------------------------------------------------------------------------
// 逐次表示方式の印刷ルーチン
// PageNumberによって処理を分岐
//-----------------------------------------------------------------------------
procedure TQPrint2.PrintRoutine;
begin
if FplPrev.PageNumber = 1 then begin
//1頁目は表のタイトルを印刷
DM1.Query1.First;
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(80);
FplPrev.TextRectJust(FVKeisenPos[0] + 500,
FVKeisenPos[5] - 500,
250,
400,
'表の印刷例');
//1頁分のデータを描画
PrintOnePage(FStartPosY1, FEndPosY, FRowCount1);
//罫線を描画
PageKeisen(FStartPosY1, FEndPosY, FRowCount1);
end else begin
DM1.Query1.First;
if FplPrev.PageNumber = 2 then begin
DM1.Query1.MoveBy(FRowCount1 - 1); //-1はタイトル行の分
end else begin
DM1.Query1.MoveBy((FRowCount1 - 1) + (FplPrev.PageNumber - 2) * (FRowCount2 - 1));
end;
//1頁分のデータを描画
PrintOnePage(FStartPosY2, FEndPosY, FRowCount2);
//罫線を描画
PageKeisen(FStartPosY2, FEndPosY, FRowCount2);
end;
end;
//-----------------------------------------------------------------------------
// 表の罫線部分と頁番号と印刷日時を印刷
//
// 共通部分と考えられる表の罫線と頁数と印刷日時を印刷するルーチン.
// つまり書類の背景と言える部分のコード.
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
// RowCnt 行数.1頁と2頁以降では異なる
//-----------------------------------------------------------------------------
procedure TQPrint2.PageKeisen(Yt, Yb, RowCnt: Integer);
var
LLeft : Integer;
LRight : Integer;
LTop : Integer;
LBottom : Integer;
LPageStr : String;
LDateStr : String;
LRowNo : Integer;
LColNo : Integer;
begin
LLeft := FVKeisenPos[0];
LRight := FVKeisenPos[Length(FVKeisenPos) - 1];
FplPrev.LineWidth(1);
//横罫線はタイトル行も含めるので+1
for LRowNo := 1 to RowCnt + 1 do begin
LTop := Yt + (LRowNo - 1) * FRowHeight;
FplPrev.Line(LLeft, LRight, LTop, LTop);
end;
//縦罫線の一番下のY座標値
LBottom := Yt + RowCnt * FRowHeight;
//縦罫線の描画
for LColNo := 0 to Length(FVKeisenPos) - 1 do begin
FplPrev.Line(FVKeisenPos[LColNo], FVKeisenPos[LColNo], Yt, LBottom);
end;
//頁番号と頁数を描画
LPageStr := '- ' + IntToStr(FplPrev.PageNumber) + '/' + IntToStr(FPageCount) + ' -';
FplPrev.FontSize(12);
FplPrev.TextOutCC(FplPrev.PaperWidth div 2, Yb + 50, LPageStr);
//印刷日時を描画.書類は何時誰がが基本
LDateStr := '印刷日時 ' + FormatDateTime('yyyy/mm/dd hh:nn', Now);
FplPrev.FontName('MS 明朝');
FplPrev.FontSize(8);
FplPrev.TextOutRC(LRight, Yb + 50, LDateStr);
end;
//-----------------------------------------------------------------------------
// Y座標の上端,下端と行高さから描画可能な行数を算出
// 先読み方式と同じコード
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
//-----------------------------------------------------------------------------
function TQPrint2.GetRowCnt(Yt, Yb: Integer): Integer;
begin
Result := Trunc((Yb - Yt) / FRowHeight);
end;
//-----------------------------------------------------------------------------
// 1頁分の印刷ルーチン 先読み方式と同じコード
// RowHの行高でRowCnt行分だけ描画する
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
//-----------------------------------------------------------------------------
procedure TQPrint2.PrintOnePage(Yt, Yb, RowCnt: Integer);
var
LX1 : Integer;
LX2 : Integer;
LY1 : Integer;
LY2 : Integer;
LText : String;
LRowNo : Integer;
LColNo : Integer;
begin
//タイトル行である1行目は色付きセルとする
FplPrev.BrushColor($00D9FFD9);
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(45);
FplPrev.FillRect(FVKeisenPos[0], FVKeisenPos[5], Yt, Yt + FRowHeight);
for LRowNo := 1 to RowCnt do begin
for LColNo := 0 to Length(FVKeisenPos) - 2 do begin
LX1 := FVKeisenPos[LColNo];
LX2 := FVKeisenPos[LColNo + 1];
LY1 := Yt + (LRowNo - 1) * FRowHeight;
LY2 := Yt + LRowNo * FRowHeight;
{タイトル行}
if LRowNo = 1 then begin
FplPrev.TextRectCC(LX1, LX2, LY1, LY2, DM1.Query1.Fields[LColNo].FieldName);
end else begin
//データの描画
LText := '';
//データ項目値に応じて描画
case LColNo of
0: //CustNo
begin
LText := IntToStr(DM1.Query1.FieldByName('CustNo').AsInteger);
FplPrev.TextRectRC(LX1, LX2 - 15, LY1, LY2, LText);
end;
1: //Company
begin
LText := DM1.Query1.FieldByName('Company').AsString;
FplPrev.TextRectLC(LX1 + 15, LX2, LY1, LY2, LText);
end;
2: //Zip
begin
LText := DM1.Query1.FieldByName('Zip').AsString;
FplPrev.TextRectRC(LX1, LX2 - 12, LY1, LY2, LText);
end;
3: //Addr1
begin
LText := DM1.Query1.FieldByName('Addr1').AsString;
FplPrev.TextRectLC(LX1 + 15, LX2, LY1, LY2, LText);
end;
4: //Phone
begin
LText := DM1.Query1.FieldByName('Phone').AsString;
FplPrev.TextRectLC(LX1 + 15, LX2, LY1, LY2, LText);
end;
end;
end;
end;
//タイトル行でなければ次のデータ
if LRowNo > 1 then DM1.Query1.Next;
//データがなければ終了
if DM1.Query1.Eof then Break;
end;
end;
end.
リスト4
Unit3 のコード.画像とメモ項目データの表示 (先読み方式) |
unit Unit3;
interface
uses Windows,Db,Graphics;
type
TQPrint3 = class
private
procedure PageKeisen(Yt, Ytt, Yb, RowCnt: Integer);
function GetRowCnt(Yt, Yb: Integer): Integer;
procedure PrintOnePage(Yt, Ytt, Yb, RowCnt: Integer);
procedure PrintOneGraphic(X1, X2, Y1, Y2: Integer; FldName: TField);
procedure PrintOneNote(X1, X2, Y1, Y2: Integer; FldName: TField);
procedure PrintOneNoteEx(X1, X2, Y1, Y2: Integer; FldName: TField);
public
procedure PrintBlob;
end;
var
QPrint3: TQPrint3;
implementation
uses
Messages, SysUtils, Classes, Controls, Forms, Dialogs,
Math, DM1Unit, plPrev, QueryPrintUnit, TextUtils;
{ TQPrint3 }
// 共通変数
// 見やすいようにここに書いているが実際にはprivate,public部がいいだろう
var
FTitleHeight : Integer; //タイトル行の高さ
FStartPosY : Integer; //タイトル行を除いた表の上端値
FEndPosY : Integer; //表下端の下限値
FRowHeight : Integer; //行高
FRowCount : Integer; //1頁目の行数
FRecordCount : Integer; //レコード数
FPageCount : Integer; //総頁数
FVKeisenPos : array[0..3] of Integer; //縦罫線の位置
FplPrev : TplPrev; //印刷プレビュー制御コンポ
//-----------------------------------------------------------------------------
// 各種の値を計算してから描画
//
// 行の高さを決めれば1頁に印刷可能な行数が決まる(行数を決定してから行高さを
// 決定する場合も考えられる.あるいは指定の形式の場合は行高さも行数も決められ
// ていることもある).
// ここではA4縦(210.0mm,297.0mmと仮定)で行高さを10.0mmとし,1頁目はタイトル
// の印刷分を空ける
//-----------------------------------------------------------------------------
procedure TQPrint3.PrintBlob;
var
i : Integer;
begin
//plPrevはForm1のplPrev1を使用
FplPrev := Form1.plPrev1;
FVKeisenPos[0] := 150;
FVKeisenPos[1] := 350;
FVKeisenPos[2] := 800;
FVKeisenPos[3] := 1970;
FTitleHeight := 50;
FStartPosY := 300;
FEndPosY := 2700;
FRowHeight := 400;
//QueryをOpenする.項目名に空白文字項目があるので""を付加
with DM1.Query1 do begin
Close;
SQL.CLEAR;
SQL.Add('SELECT Count(*) as RecCnt FROM "BIOLIFE.DB" BIOLIFE ');
Open;
FRecordCount := DM1.Query1.FieldByName('RecCnt').AsInteger;
Close;
SQL.CLEAR;
SQL.Add('SELECT ');
SQL.Add('BIOLIFE."Species No",');
SQL.Add('BIOLIFE."Common_Name",');
SQL.Add('BIOLIFE."Notes",');
SQL.Add('BIOLIFE."Graphic"');
SQL.Add('FROM "BIOLIFE.DB" BIOLIFE');
Open;
end;
//1頁の印刷可能行数
FRowCount := GetRowCnt(FStartPosY, FEndPosY);
//FPageCntが総頁数.切上げ計算しないと頁数不足
FPageCount := Ceil(FRecordCount / FRowCount);
FplPrev.Title := '画像データの出力例';
FplPrev.BeginDoc;
try
for i := 1 to FPageCount do begin
PrintOnePage(FStartPosY, FTitleHeight, FEndPosY, FRowCount); //1頁分描画
PageKeisen (FStartPosY, FTitleHeight, FEndPosY, FRowCount); //罫線を描画
if i < FPageCount then FplPrev.NewPage;
end;
finally
FplPrev.EndDoc;
end;
//Showで表示してしまうと次行でクエリーが閉じてしまう
FplPrev.ShowModal;
DM1.Query1.Close;
end;
//-----------------------------------------------------------------------------
// 1頁分の印刷ルーチン
//
// RowHの行高でRowCnt行分だけ描画する
// Yt 表の上端Y座標
// Ytt タイトル行の高さ
// Yb 表の下端Y座標.
// RowCnt 行数
//-----------------------------------------------------------------------------
procedure TQPrint3.PrintOnePage(Yt, Ytt, Yb, RowCnt: Integer);
var
LX1 : Integer;
LX2 : Integer;
LY1 : Integer;
LY2 : Integer;
LSNo : Double;
LSNs : String;
LGraphFld : TField;
LMemoFld : TField;
LRowNo : Integer;
LColNo : Integer;
begin
//タイトル行は色付きセルとする
FplPrev.BrushColor($00D9FFD9);
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(60);
FplPrev.FillRect(FVKeisenPos[0], FVKeisenPos[Length(FVKeisenPos) - 1], Yt - Ytt, Yt);
//頁タイトル
LX1 := (FVkeisenPos[0] + FVKeisenPos[Length(FVKeisenPos) - 1]) div 2;
FplPrev.TextOutCB(LX1, Yt - Ytt - 20, 'BIOLIFE.DB');
//表のタイトル部の文字列
FplPrev.FontHeight(35);
for LColNo := 0 to Length(FVKeisenPos) - 2 do begin
LX1 := FVKeisenPos[LColNo];
LX2 := FVKeisenPos[LColNo + 1];
FplPrev.TextRectCC(LX1, LX2, Yt - Ytt, Yt, DM1.Query1.Fields[LColNo].FieldName);
end;
//データ部の描画
LGraphFld := DM1.Query1.FieldByName('Graphic');
LMemoFld := DM1.Query1.FieldByName('Notes');
for LRowNo := 1 to RowCnt do begin
LY1 := Yt + (LRowNo - 1) * FRowHeight;
LY2 := Yt + LRowNo * FRowHeight;
//Species No項目
LSNo := DM1.Query1.FieldByName('Species No').AsFloat;
FplPrev.TextRectCC(FVKeisenPos[0], FVKeisenPos[1], LY1, LY2, FloatToStr(LSNo));
//Graphic項目
PrintOneGraphic(FVkeisenPos[1] + 50,
FVKeisenPos[2] - 50,
LY1 + 50,
LY2 - 50,
LGraphFld);
//Notes項目
PrintOneNoteEx(FVkeisenPos[2] + 20,
FVKeisenPos[3] - 20,
LY1 + 20,
LY2 - 20,
LMemoFld);
//Common_Name項目
LSNs := DM1.Query1.FieldByName('Common_Name').AsString;
FplPrev.TextRectCB(FVkeisenPos[1], FVKeisenPos[2], LY1, LY2 - 20, LSNs);
DM1.Query1.Next;
if DM1.Query1.Eof then Break;
end;
end;
//-----------------------------------------------------------------------------
// Y座標の上端,下端と行高さから描画可能な行数を算出
// Yt 表の上端Y座標
// Yb 表の下端Y座標.
//-----------------------------------------------------------------------------
function TQPrint3.GetRowCnt(Yt, Yb: Integer): Integer;
begin
Result := Trunc((Yb - Yt) / FRowHeight);
end;
//-----------------------------------------------------------------------------
// 表の罫線部分の描画ルーチン
//
// 共通部分と考えられる表の罫線と頁数と印刷日時を印刷するルーチン.
// つまり,書類の背景と言える部分のコード.
// Yt 表の上端Y座標
// Ytt タイトル行の高さ
// Yb 表の下端Y座標.
// RowCnt 行数
//-----------------------------------------------------------------------------
procedure TQPrint3.PageKeisen(Yt, Ytt, Yb, RowCnt: Integer);
var
LTop : Integer;
LBotton : Integer;
LLeft : Integer;
LRight : Integer;
LPageStr : String;
LDateStr : String;
LRowNo : Integer;
LColNo : Integer;
begin
LLeft := FVKeisenPos[0];
LRight := FVKeisenPos[Length(FVKeisenPos) - 1];
FplPrev.LineWidth(1);
//タイトル行の横罫線
FplPrev.Line(LLeft, LRight, Yt - Ytt, Yt - Ytt);
//横罫線
for LRowNo := 1 to RowCnt + 1 do begin
LTop := Yt + (LRowNo - 1) * FRowHeight;
FplPrev.Line(LLeft, LRight, LTop, LTop);
end;
//縦罫線の一番下のY座標値
LBotton := Yt + RowCnt * FRowHeight;
//縦罫線の描画
for LColNo := 0 to Length(FVKeisenPos) - 1 do begin
FplPrev.Line(FVKeisenPos[LColNo], FVKeisenPos[LColNo], Yt - Ytt, LBotton);
end;
//頁番号と頁数を描画
LPageStr := '- ' + IntToStr(FplPrev.PageNumber)
+ '/' + IntToStr(FPageCount) + ' -';
FplPrev.FontSize(12);
FplPrev.TextOutCC(FplPrev.PaperWidth div 2, Yb + 50, LPageStr);
//印刷日時を描画.書類は何時誰がが基本
LDateStr := '印刷日時 ' + FormatDateTime('yyyy/mm/dd hh:nn', Now);
FplPrev.FontName('MS 明朝');
FplPrev.FontSize(8);
FplPrev.TextOutRC(LRight, Yb + 50, LDateStr);
end;
//-----------------------------------------------------------------------------
// BLOBの(ビットマップ)イメージデータを描画
// 指定枠の横または縦方向の寸法に合わせて縦横比を変更せずに描画
//
// X1 : 枠の左端X座標値
// X2 : 枠の右端X座標値
// Y1 : 枠の上端Y座標値
// Y2 : 枠の下端Y座標値
// FldName: 項目
//-----------------------------------------------------------------------------
procedure TQPrint3.PrintOneGraphic(X1, X2, Y1, Y2: Integer; FldName: TField);
var
LBitmap : TBitMap;
LBitmapH : Integer;
LBitmapW : Integer;
LRatio1 : Double;
LRatio2 : Double;
begin
LBitmap := TBitmap.Create;
try
//Graphicの内容をBitMapに読込む
LBitmap.Assign(TGraphicField(FldName));
//縦横比を変化させず枠の大きさに合わせるための簡易計算
LBitmapH := LBitmap.Height;
LBitmapW := LBitmap.Width;
LRatio1 := (X2 - X1) / (Y2 - Y1);
LRatio2 := LBitmapW / LBitmapH;
if LRatio1 > LRatio2 then begin
X2 := X1 + Trunc((Y2 - Y1) * LRatio2);
end else begin
Y2 := Y1+Trunc((X2 - X1) / LRatio2);
end;
FplPrev.StretchDrawBitmap(Rect(X1, Y1, X2, Y2), LBitmap);
finally
FreeAndNil(LBitmap);
end;
end;
//-----------------------------------------------------------------------------
// BLOBのメモデータを描画
// 指定枠内に収めて描画.枠の中に収まらない部分は描画しない
//
// X1 : 枠の左端X座標値
// X2 : 枠の右端X座標値
// Y1 : 枠の上端Y座標値
// Y2 : 枠の下端Y座標値
// FldName: 項目
//-----------------------------------------------------------------------------
procedure TQPrint3.PrintOneNote(X1, X2, Y1, Y2: Integer;
FldName: TField);
var
LStringList : TStringList;
LRect : TRect;
LuFormat : Integer;
begin
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(30);
//クリップ(印刷枠)範囲の指定
LRect := Rect(X1, Y1, X2, Y2);
//印刷書式の設定
LuFormat := DT_LEFT or DT_WORDBREAK or DT_EDITCONTROL;
LStringList := TStringList.Create;
try
//Notes(Memo)の内容をStringListに読込む
LStringList.Assign(TMemoField(FldName));
//指定領域内に出力
DrawText(FplPrev.Canvas.Handle,PChar(LStringList.Text), -1, LRect, LuFormat);
finally
FreeAndNil(LStringList);
end;
end;
//-----------------------------------------------------------------------------
// BLOBのメモデータを描画(StringListOutメソッドを使用)
// 指定枠内に収めて描画.枠の中に収まらない部分は描画しない
//
// X1 : 枠の左端X座標値
// X2 : 枠の右端X座標値
// Y1 : 枠の上端Y座標値
// Y2 : 枠の下端Y座標値
// FldName: 項目名
//-----------------------------------------------------------------------------
procedure TQPrint3.PrintOneNoteEx(X1, X2, Y1, Y2: Integer;
FldName: TField);
var
LStringList : TStringList;
LOptions : TFormatOptions;
begin
LOptions := [foJustify];
FplPrev.FontName('MS Pゴシック');
FplPrev.FontHeight(30);
LStringList := TStringList.Create;
try
//Notes(Memo)の内容をStringListに読込む
LStringList.Assign(TMemoField(FldName));
//指定領域内に出力
FplPrev.StringListOut(LStringList,
LOptions,
X1,
X2,
Y1,
Y2,
FplPrev.Canvas.Font.Height + 7);
finally
FreeAndNil(LStringList);
end;
end;
end.
|