Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2009年03月28日] [更新 2014年05月30日] Delphi サンプルプログラム集
   
012_プリンタの解像度と用紙サイズ等の取得
動作確認等 Windows 7 U64(SP1) + Delphi XE Pro
012_PrintResolution.zip [2,420 KB] 2014年05月30日版 (EXE 同梱)



  • 2013年07月20日
  • 用紙名等の配列を,動的配列を使用するコードに変更して,コードを整備
  • WORD 値の取得のキャストを PChar から Pointer に修正
  • 2014年05月30日
  • 用紙のオフセットの上下左右の計算が間違っていたのを修正




01_プリンタの解像度と用紙サイズ等の取得


印刷のプログラムを作成する際,TPrinter の Canva に印刷,つまり描画コードを書くとします.この時の座標の値はドット単位となります.例えばプリンタの解像度が 180 DPI (1 インチ当たりのドット数) では,360 は 5.08 cm に相当します.360 DPI の解像度では 2.54 cm になります.
下の図は,A5 用紙で印刷した時の解像度による違いを説明したものです.


[備考]
Delphi で印刷するということは,プリンタのキャンパス (TPrinter.Canvas) に対して描画コードを実行することです.つまり,プリンタのキャンパスに描画することです.
TImage 等の Canvas への描画と違うのは,TPrinter に対して,描画開始,改頁や終了時に専用のメソッドを実行することです.また,指定座標値の色の取得等,描画が終了していないとできない操作や,描画内容に対するマウス操作等,リアルタイムの描画操作はできません.



図1
300 DPI の解像度で,下のコードを実行した場合
図2
600 DPI の解像度で,下のコードを実行した場合
  • 文字の大きさは変わらないが,文字列の描画開始位置と,四角形の位置とサイズが違う
  • 文字のサイズはポイント数で指定している
  • 文字列の描画開始位置と,四角形の描画位置とサイズはドット数で指定している

リスト1
TPrinter オブジェクトで印刷.座標の単位はドット
実際に印刷される位置とサイズは,その時のプリンタの解像度によって異なる
このコードの実行には,uses に Printers が必要
procedure TForm1.Button2Click(Sender: TObject);
begin
  Printer.BeginDoc;
  try
    Printer.Canvas.Brush.Style := bsClear;
    Printer.Canvas.Font.Size := 50;
    Printer.Canvas.TextOut(360, 360, 'A5 縦用紙');
    Printer.Canvas.Rectangle(360, 360, 1080, 1800);
  finally
    Printer.EndDoc;
  end;
end;


線や文字,あるいは図形を希望の位置と大きさで印刷するには,そのプリンタの現在の解像度を知って,換算しなければなりません.特に,別のプリンタでも同じ位置とサイズで印刷するためには必要な情報です.次のコードはこの用途のために,プリンタの解像度や用紙サイズを取得して表示するテストプログラムです.
これらの値は,GetDeviceCaps という関数を使用して取得することができます.
[定数] は,WinSpool.pas で定義されている定数名です.

座標値やサイズの換算には,拙作印刷プレビュー制御コンポーネントで使用しているマッピングという手法も利用できます.


図3
設計時画面
図4
実行時画面
  • コンボボックスでプリンタを選択
  • [プリンタの設定ダイアログ] で用紙サイズ等を変更すると,その値を表示

リスト2
プリンタの現在の解像度や用紙サイズを取得して表示
unit Resolution_PaperSizeUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Grids;

type
  TForm1 = class(TForm)
    Panel5: TPanel;
    Panel3: TPanel;
    Panel1: TPanel;
    PrinterSetupDialog1: TPrinterSetupDialog;
    StringGrid1: TStringGrid;
    Button1: TButton;
    ComboBox1: TComboBox;
    procedure FormShow(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure Button1Click(Sender: TObject);
    procedure ComboBox1CloseUp(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses Printers, WinSpool,Types;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォームを表示する時の処理
//  プリンタのリスト作成
//  StringGridのタイトル部分にタイトル文字を表示
//
//  StringGrid1.BorderStyle := bsNone;
//  StringGrid1.Enabled := True;
//  StringGrid1.Options := [goRowSelect];
//  にしている
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  i : Integer;
begin
  StringGrid1.Options := StringGrid1.Options + [goColSizing];

  //プリンタのリストを作成
  //PRINTER_INFO_4構造体から取得した方が正確
  //Printerオブジェクトから取得したプリンタ名と順番や内容が異なる場合がある
  ComboBox1.Items.Clear;
  ComboBox1.Items.Assign(Printer.Printers);
  ComboBox1.ItemIndex := Printer.PrinterIndex;
  ComboBox1CloseUp(nil);

  i :=0;
  StringGrid1.Cells[0, i] := '取得情報の内容';
  StringGrid1.Cells[1, i] := '定数';
  StringGrid1.Cells[2, i] := '値';

  inc(i);
  StringGrid1.Cells[0, i] := '横方向の解像度';
  StringGrid1.Cells[1, i] := 'LOGPIXELSX';

  inc(i);
  StringGrid1.Cells[0, i] := '縦方向の解像度';
  StringGrid1.Cells[1, i] := 'LOGPIXELSY';

  inc(i);
  StringGrid1.Cells[0, i] := '用紙幅(ドット)';
  StringGrid1.Cells[1, i] := 'PHYSICALWIDTH';

  inc(i);
  StringGrid1.Cells[0, i] := '用紙高さ(ドット)';
  StringGrid1.Cells[1, i] := 'PHYSICALHEIGHT';

  inc(i);
  StringGrid1.Cells[0, i] := '用紙幅';
  StringGrid1.Cells[1, i] := 'PHYSICALWIDTH';

  inc(i);
  StringGrid1.Cells[0, i] := '用紙高さ';
  StringGrid1.Cells[1, i] := 'PHYSICALHEIGHT';

  inc(i);
  StringGrid1.Cells[0, i] := '印刷可能領域の幅';
  StringGrid1.Cells[1, i] := 'HORZRES';

  inc(i);
  StringGrid1.Cells[0, i] := '印刷可能領域の高さ';
  StringGrid1.Cells[1, i] := 'VERTRES';

  inc(i);
  StringGrid1.Cells[0, i] := '上端オフセット';
  StringGrid1.Cells[1, i] := 'PHYSICALOFFSETY';

  inc(i);
  StringGrid1.Cells[0, i] := '印刷可能下端Y座標';
  StringGrid1.Cells[1, i] := 'PHYSICALOFFSETY + VERTRES';

  inc(i);
  StringGrid1.Cells[0, i] := '左端オフセット';
  StringGrid1.Cells[1, i] := 'PHYSICALOFFSETX';

  inc(i);
  StringGrid1.Cells[0, i] := '印刷可能右端X座標';
  StringGrid1.Cells[1, i] := 'PHYSICALOFFSETX + HORZRES';

  inc(i);
  StringGrid1.Cells[0, i] := 'ピクセル当たりのカラービット数';
  StringGrid1.Cells[1, i] := 'BITSPIXEL';
end;

//=============================================================================
//  プリンタの設定ダイアログを表示
//  ここで用紙サイズや解像度を変更して,結果を確認できる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  if ComboBox1.ItemIndex<0 then exit;

  //選択したプリンタを現在のプリンタとする
  if PrinterSetupDialog1.Execute then begin
    ComboBox1CloseUp(nil);
  end;
end;

//=============================================================================
//  ComboBox1のOnCloseUpイベント処理
//
//  StringGrid1へ結果を表示
//  ComboBox1で選択したプリンタの現在の用紙サイズ等を表示
//=============================================================================
procedure TForm1.ComboBox1CloseUp(Sender: TObject);
var
  i           : Integer;
  PrtHandle   : THandle;
  XDPI        : Integer;
  YDPI        : Integer;
  TempInt     : Integer;
  TempDouble  : Double;
begin
  if ComboBox1.ItemIndex<0 then exit;

  //選択したプリンタを現在のプリンタとする
  Printer.PrinterIndex := ComboBox1.ItemIndex;

  PrtHandle := Printer.Handle;
  i := 1;

  //以下,現在のプリンタに関する情報を取り出すコード

  //横と縦方向の解像度
  XDPI               := GetDeviceCaps(PrtHandle, LOGPIXELSX);
  StringGrid1.Cells[2, i] := IntToStr(XDPI) + ' [DPI]';
  inc(i);
  YDPI               := GetDeviceCaps(PrtHandle, LOGPIXELSY);
  StringGrid1.Cells[2, i] := IntToStr(YDPI) + ' [DPI]';

  //用紙幅と高さ(ドット)
  inc(i);
  StringGrid1.Cells[2, i] := IntToStr(GetDeviceCaps(PrtHandle,PHYSICALWIDTH)) +
                             ' [dot]';
  inc(i);
  StringGrid1.Cells[2, i] := IntToStr(GetDeviceCaps(PrtHandle, PHYSICALHEIGHT)) +
                             ' [dot]';

  //用紙幅と高さ(換算)
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, PHYSICALWIDTH);
  TempDouble         := TempInt*25.4/XDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, PHYSICALHEIGHT);
  TempDouble         := TempInt * 25.4 / YDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);

  //印刷可能領域の幅と高さ
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, HORZRES);
  TempDouble         := TempInt * 25.4 / XDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, VERTRES);
  TempDouble         := TempInt * 25.4 / YDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);

  //上下左右のオフセット
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, PHYSICALOFFSETY);
  TempDouble         := TempInt * 25.4 / YDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]',[TempDouble]);
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, PHYSICALOFFSETY) +
                        GetDeviceCaps(PrtHandle, VERTRES);
  TempDouble         := TempInt * 25.4 / YDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);

  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, PHYSICALOFFSETX);
  TempDouble         := TempInt * 25.4 / XDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);
  inc(i);
  TempInt            := GetDeviceCaps(PrtHandle, PHYSICALOFFSETX) +
                        GetDeviceCaps(PrtHandle, HORZRES);
  TempDouble         := TempInt * 25.4 / XDPI;
  StringGrid1.Cells[2, i] := Format('%8.1f [mm]', [TempDouble]);

  //ピクセル当たりのカラービット数
  inc(i);
  StringGrid1.Cells[2, i] := IntToStr(GetDeviceCaps(PrtHandle, BITSPIXEL)) +
                             ' [bit]';
end;

//=============================================================================
//  StringGrid1のOnDrawCellイベント処理
//  StringGrid1の描画処理
//
//  プログラムの動作自体には直接関係なし.なくてもよい
//=============================================================================
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  uFormat : Cardinal;
begin
  if (gdFixed in State) or (ACol<2) then begin
    with StringGrid1.Canvas do begin
      Brush.Color := $00EBEBEB;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Left  := Rect.Left+5;
      uFormat    := DT_LEFT or DT_SINGLELINE  or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect,uFormat);
    end;
  end else begin
    with StringGrid1.Canvas do begin
      Brush.Color := clWhite;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Right := Rect.Right-5;
      uFormat    := DT_RIGHT or DT_SINGLELINE or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect,uFormat);
    end;
  end;
end;

end.




02_使用可能な用紙名のリスト


使用可能な用紙サイズをリスト表示します.印刷用紙を設定する時の参考用です.
どんな用紙が使用可能かは,プリンタドライバによります.プリントサーバに登録されている用紙の全てが使用できるわけではありません.


図5
設計時画面
図6
実行画面
  • コンボボックスでプリンタを選択

リスト3
使用可能な用紙のリストを作成
unit PaperNameListUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Grids;

type
  TForm1 = class(TForm)
    Panel5: TPanel;
    Panel3: TPanel;
    Panel1: TPanel;
    StringGrid1: TStringGrid;
    ComboBox1: TComboBox;
    procedure FormShow(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ComboBox1CloseUp(Sender: TObject);
  private
    { Private 宣言 }
    PaperList : TStringList;
    SourceList : TStringList;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses Printers, WinSpool, PaperListUnit;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォームを表示する時の処理
//  プリンタのリストを作成
//  用紙サイズとビン装置のリストを別ユニットに用意した関数で作成
//  ただし,このテストプログラムでは用紙名のリストしか使用しない
//
//  StringGrid1.BorderStyle := bsNone;
//  StringGrid1.Enabled := True;
//  StringGrid1.Options := [goRowSizing,goRowSelect];
//  にしている
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
  StringGrid1.Options := StringGrid1.Options + [goColSizing];

  PaperList  := TStringList.Create;
  SourceList := TStringList.Create;
  MakePaperList(PaperList,SourceList);

  ComboBox1.Items.Clear;
  ComboBox1.Items.Assign(Printer.Printers);
  ComboBox1.ItemIndex := Printer.PrinterIndex;
  ComboBox1CloseUp(nil);

  StringGrid1.Cells[0, 0] := '用紙名';
  StringGrid1.Cells[1, 0] := '定数';
  StringGrid1.Cells[2, 0] := '値';
end;

//=============================================================================
//  終了時の処理
//  TStringListを解放
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FreeAndNil(PaperList);
  FreeAndNil(SourceList);
end;

//=============================================================================
//  ComboBox1のOnCloseUpイベント処理
//  コンボボックスで選択したプリンタで使用可能な用紙リストを作成
//=============================================================================
procedure TForm1.ComboBox1CloseUp(Sender: TObject);
type
  //用紙名リスト用.用紙名の文字数の最大は64
  TPaperName = array [0..63] of Char;

var
  ADevice      : array [0..MAX_PATH-1] of Char;
  ADriver      : array [0..MAX_PATH-1] of Char;
  APort        : array [0..MAX_PATH-1] of Char;
  ADeviceMode  : THandle;
  Count        : Integer;
  AIndex       : Integer;
  PaperNames   : array of TPaperName;
  PaperNumbers : array of WORD;
  i            : Integer;
  j            : Integer;
begin
  if ComboBox1.ItemIndex < 0 then exit;

  //選択したプリンタを現在のプリンタとする
  Printer.PrinterIndex := ComboBox1.ItemIndex;
  //現在のプリンタに関する情報を取り出す
  Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);

  //そのプリンタADeviceのAPortの用紙名の数を取得
  Count := DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, nil, nil);

  //その分だけ用紙名配列の長さと用紙番号の配列の長さを確保
  SetLength(PaperNames,   Count);
  SetLength(PaperNumbers, Count);

  //その配列に用紙名と用紙番号を取得
  DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, PChar(PaperNames),     nil);
  DeviceCapabilities(ADevice, APort, DC_PAPERS,     Pointer(PaperNumbers), nil);


  //StringGrid1の行数
  StringGrid1.RowCount := Count + 1;
  //表示開始時は1行目を選択
  StringGrid1.Row := 1;

  //StringGrid1に用紙名等を表示
  if Count < 1 then begin
    StringGrid1.RowCount := 2;
    StringGrid1.Cells[0, 1] := '-';
    StringGrid1.Cells[1, 1] := '-';
    StringGrid1.Cells[2, 1] := '';
  end else begin
    for i := 0 to Count - 1 do  begin
      //用紙名と用紙番号を表示
      StringGrid1.Cells[0, i + 1] := String(PaperNames[i]);
      StringGrid1.Cells[2, i + 1] := IntToStr(PaperNumbers[i]);

      //用紙番号に相当する定数を検索して表示
      AIndex := Integer(PaperNumbers[i]);
      for j := 0 to PaperList.Count - 1 do begin
        if AIndex = Integer(PaperList.Objects[j]) then begin
          StringGrid1.Cells[1, i + 1] := PaperList[j];
          break;
        end;
      end;
    end;  //enf for
  end;
end;

//=============================================================================
//  StringGrid1のOnDrawCellイベント処理
//  StringGrid1の描画処理
//
//  プログラムの動作自体には直接関係なし.実際にはなくてもよい
//=============================================================================
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  uFormat : Cardinal;
begin
  if (gdFixed in State) then begin
    with StringGrid1.Canvas do begin
      Brush.Color := $00EBEBEB;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Left  := Rect.Left + 5;
      uFormat    := DT_LEFT or DT_SINGLELINE  or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect, uFormat);
    end;
  end else begin
    with StringGrid1.Canvas do begin
      if gdSelected in State then begin
        Brush.Color := $00EFEED3;
      end else begin
        Brush.Color := clWhite;
      end;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Left  := Rect.Left + 5;
      uFormat    := DT_LEFT or DT_SINGLELINE  or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect, uFormat);
    end;
  end;
end;

end.


上のコードは,TStringGrid に結果を表示し,用紙の定数名を表示しています.更にグリッドのセルの色を変更したりしているため,冗長になっています.
単に用紙名と用紙番号を表示するだけであれば,短いコードで済みます.下のコードは TListBox に用紙名と用紙番号だけを表示するだけのサンプルです.


//=============================================================================
//  現在のプリンタで使用可能な用紙番号と用紙名を取得
//  usesにPrintersとWinSpoolが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
type
  //用紙名リスト用.用紙名の文字数の最大は64
  TPaperName = array [0..63] of Char;

var
  ADevice       : array [0..MAX_PATH-1] of Char;
  ADriver       : array [0..MAX_PATH-1] of Char;
  APort         : array [0..MAX_PATH-1] of Char;
  ADeviceMode   : THandle;
  Count         : Integer;
  PaperNames    : array of TPaperName;
  PaperNumbers  : array of WORD;
  i             : Integer;
begin
  //プリンタに関する情報を取り出す
  Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);

  //APortに接続しているプリンタADeviceのビンの数を取得
  Count := DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, nil, nil);

  //その数分だけ用紙名と用紙番号用配列の要素数を確保
  SetLength(PaperNames,  Count);
  SetLength(PaperNumbers, Count);

  //その配列に用紙名と用紙番号を取得
  DeviceCapabilities(ADevice, APort, DC_PAPERNAMES, PChar(PaperNames),    nil);
  DeviceCapabilities(ADevice, APort, DC_PAPERS,     Pointer(PaperNumbers), nil);

  //ListBox1に用紙名等を表示
  for i := 0 to Count - 1 do  begin
    ListBox1.Items.Add(Format('%4d', [PaperNumbers[i]]) + '   ' + PaperNames[i]);
  end;
end;




03_使用可能な解像度のリスト


プリンタがサポートしている解像度のリストを取得するテストプログラムです.
プリンタによっては [品質] という設定項目がある場合がありますが,これは必ずしも解像度,つまり DPI を意味するとは限りません. 解像度の設定がないプリンタドライバもあります.


図7
設計時画面
図8
実行画面
  • コンボボックスでプリンタを選択

リスト4
使用可能な解像度のリストを作成
unit ResolutionListUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Grids;

type
  TForm1 = class(TForm)
    Panel5: TPanel;
    Panel3: TPanel;
    Panel1: TPanel;
    StringGrid1: TStringGrid;
    ComboBox1: TComboBox;
    procedure FormShow(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure ComboBox1CloseUp(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses Printers, WinSpool;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォームを表示する時の処理
//
//  StringGrid1.BorderStyle := bsNone;
//  StringGrid1.Enabled := True;
//  StringGrid1.Options := [goRowSelect];
//  にしている
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
  StringGrid1.Options := StringGrid1.Options + [goColSizing];

  //プリンタのリストを作成
  //Printerオブジェクトから取得したプリンタ名と順番や内容が異なる場合がある
  ComboBox1.Items.Clear;
  ComboBox1.Items.Assign(Printer.Printers);
  ComboBox1.ItemIndex := Printer.PrinterIndex;
  ComboBox1CloseUp(nil);

  StringGrid1.Cells[0,0] := '横方向解像度';
  StringGrid1.Cells[1,0] := '縦方向解像度';
end;

//=============================================================================
//  コンボボックスで選択したプリンタで使用可能な解像度(DPI)のリストを作成
//=============================================================================
procedure TForm1.ComboBox1CloseUp(Sender: TObject);
var
  ADevice     : array [0..MAX_PATH-1] of Char;
  ADriver     : array [0..MAX_PATH-1] of Char;
  APort       : array [0..MAX_PATH-1] of Char;
  ADeviceMode : THandle;
  Count       : Integer;
  DPIs        : array of TSize;
  i           : Integer;
begin
  if ComboBox1.ItemIndex < 0 then exit;

  //選択したプリンタを現在のプリンタとする
  Printer.PrinterIndex := ComboBox1.ItemIndex;
  //現在のプリンタに関する情報を取り出す
  Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);

  //APortに接続しているプリンタADeviceがサポートする解像度の数を取得
  Count := DeviceCapabilities(ADevice, APort, DC_ENUMRESOLUTIONS, nil, nil);

  //プリンタが解像度の変更をサポートしていない場合
  //DEVMODEのdmFielsのDM_PRINTQUALITYビットが0
  if Count < 1 then begin
    StringGrid1.RowCount    := 2;
    StringGrid1.Cells[0, 1] := '-';
    StringGrid1.Cells[1, 1] := '-';
  end else begin
    //解像度の数だけTSizeの配列要素を確保
    SetLength(DPIs, Count);

    StringGrid1.RowCount := Count + 1;
    StringGrid1.Row      := 1;

    //DPIsに解像度のリストを取得
    DeviceCapabilities(ADevice, APort, DC_ENUMRESOLUTIONS, Pointer(DPIs), nil);

    //StringGrid1に横と縦の解像度を表示
    for i := 0 to Count - 1 do  begin
      StringGrid1.Cells[0, i + 1] := IntToStr(DPIs[i].cx);
      StringGrid1.Cells[1, i + 1] := IntToStr(DPIs[i].cy);
    end;
  end;
end;

//=============================================================================
//  StringGrid1のOnDrawCellイベント処理
//  StringGrid1の描画処理
//
//  プログラムの動作自体には直接関係なし.実際にはなくてもよい
//=============================================================================
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  uFormat : Cardinal;
begin
  if (gdFixed in State) then begin
    with StringGrid1.Canvas do begin
      Brush.Color := $00EBEBEB;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Left  := Rect.Left + 5;
      uFormat    := DT_CENTER or DT_SINGLELINE  or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect, uFormat);
    end;
  end else begin
    with StringGrid1.Canvas do begin
      if gdSelected in State then begin
        Brush.Color := $00EFEED3;
      end else begin
        Brush.Color := clWhite;
      end;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Right := Rect.Right - 7;
      uFormat    := DT_RIGHT or DT_SINGLELINE or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect, uFormat);
    end;
  end;
end;

end.




04_使用可能なビン装置(用紙供給装置)のリスト


ビン装置,用紙供給装置をリストするテストプログラムです.


図9
設計時画面
図10
実行画面
  • コンボボックスでプリンタを選択

リスト5
使用可能なビン装置のリストを作成
unit BinNameLIstUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Grids;

type
  TForm1 = class(TForm)
    Panel5: TPanel;
    Panel3: TPanel;
    Panel1: TPanel;
    StringGrid1: TStringGrid;
    ComboBox1: TComboBox;
    procedure FormShow(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ComboBox1CloseUp(Sender: TObject);
  private
    { Private 宣言 }
    PaperList : TStringList;
    SourceList : TStringList;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses Printers, WinSpool, PaperListUnit;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォームを表示する時の処理
//
//  用紙サイズとビン装置のリストを別ユニットに用意した関数で作成
//  ただし,このテストプログラムではビン装置のリストしか使用しない
//
//  プリンタのリストを作成
//  Printerオブジェクトから取得したプリンタ名と順番や内容が異なる場合がある
//
//  StringGrid1.BorderStyle := bsNone;
//  StringGrid1.Enabled := True;
//  StringGrid1.Options := +[goRowSelect];
//  にしている
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
  StringGrid1.Options := StringGrid1.Options + [goColSizing];

  PaperList  := TStringList.Create;
  SourceList := TStringList.Create;
  MakePaperList(PaperList,SourceList);

  ComboBox1.Items.Clear;
  ComboBox1.Items.Assign(Printer.Printers);
  ComboBox1.ItemIndex := Printer.PrinterIndex;
  ComboBox1CloseUp(nil);

  StringGrid1.Cells[0,0] := 'ビン名称';
  StringGrid1.Cells[1,0] := '定数';
  StringGrid1.Cells[2,0] := '値';
end;

//=============================================================================
//  終了時の処理
//  TStringListを解放
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    FreeAndNil(PaperList);
    FreeAndNil(SourceList);
end;

//=============================================================================
//  ComboBox1のOnCloseUpイベント処理
//  コンボボックスで選択したプリンタで使用可能なビン装置のリストを作成
//=============================================================================
procedure TForm1.ComboBox1CloseUp(Sender: TObject);
type
  //ビン名称リスト用.ビン名称文字列の最大は24
  TBinName = array [0..23] of Char;

var
  ADevice     : array [0..MAX_PATH-1] of Char;
  ADriver     : array [0..MAX_PATH-1] of Char;
  APort       : array [0..MAX_PATH-1] of Char;
  ADeviceMode : THandle;
  Count       : Integer;
  BinNames    : array of TBinName;
  BinNumbers  : array of WORD;
  i           : Integer;
  j           : Integer;
  AIndex      : Integer;
begin
  if ComboBox1.ItemIndex < 0 then exit;

  //選択したプリンタを現在のプリンタとする
  Printer.PrinterIndex := ComboBox1.ItemIndex;
  //現在のプリンタに関する情報を取り出す
  Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);

  //APortに接続しているプリンタADeviceのビン装置の数を取得
  Count := DeviceCapabilities(ADevice, APort, DC_BINNAMES, nil, nil);

  //ビン名称とビン番号の配列の要素数を設定
  SetLength(BinNames,   Count);
  SetLength(BinNumbers, Count);

  //確保したメモリにビン名称とビン番号がある
  DeviceCapabilities(ADevice, APort, DC_BINNAMES, PChar(BinNames),     nil);
  DeviceCapabilities(ADevice, APort, DC_BINS,     Pointer(BinNumbers), nil);


  //StringGridにビン装置名称とビン装置番号を表示
  if Count < 1 then begin
    StringGrid1.RowCount    := 2;
    StringGrid1.Cells[0, 1] := '-';
    StringGrid1.Cells[1, 1] := '-';
  end else begin
    StringGrid1.RowCount := Count + 1;
    StringGrid1.Row      := 1;

    for i := 0 to Count - 1 do  begin
      StringGrid1.Cells[0, i + 1] := String(BinNames[i]);
      StringGrid1.Cells[1, i + 1] := '';
      StringGrid1.Cells[2, i + 1] := IntToStr(BinNumbers[i]);

      //ビン番号
      //ビン番号に相当する定数変数名を検索
      AIndex := Integer(BinNumbers[i]);
      for j := 0 to SourceList.Count - 1 do begin
        if AIndex = Integer(SourceList.Objects[j]) then begin
          StringGrid1.Cells[1, i + 1] := SourceList[j];
          break;
        end;
      end;
    end;
  end;
end;

//=============================================================================
//  StringGrid1のOnDrawCellイベント処理
//  StringGrid1の描画処理
//
//  プログラムの動作自体には直接関係なし.実際にはなくてもよい
//=============================================================================
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  uFormat : Cardinal;
begin
  if (gdFixed in State) then begin
    with StringGrid1.Canvas do begin
      Brush.Color := $00EBEBEB;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Left  := Rect.Left+5;
      uFormat    := DT_LEFT or DT_SINGLELINE  or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect, uFormat);
    end;
  end else begin
    with StringGrid1.Canvas do begin
      if gdSelected in State then begin
        Brush.Color := $00EFEED3;
      end else begin
        Brush.Color := clWhite;
      end;
      FillRect(Rect);

      Font.Color := clBlack;
      Rect.Left  := Rect.Left+5;
      uFormat    := DT_LEFT or DT_SINGLELINE  or DT_VCENTER;
      DrawText(Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1, Rect, uFormat);
    end;
  end;
end;

end.