旧Delphi FAQ - VCL(3)

Abstract: このQ&Aは、旧www.borland.co.jp に掲載されていた記事を転載したものです。記事は掲載時点の情報をあるがままに掲載しており、新バージョンでのご利用においては、コンポーネントやAPIの仕様変更等によりご利用いただけない場合がありますのでご留意ください。

    文字列を元にフォームを作成

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

型名を指定する文字列を元にして Delphi のフォームを作成する方法を記述します。以下のサンプルコードを参照してください。

型名を表す文字列を元にしてフォームを作成するには、まず、Delphi に型を登録する必要があります。型を登録するには、RegisterClass 関数を使用します。RegisterClass のプロトタイプは以下の通りです。

procedure RegisterClass(AClass: TPersistentClass);

AClass は TPersistent のクラスです。言い換えると、登録しようとするクラスは、どこかの段階で TPersistent の子孫でなければいけません。フォームなど Delphi のすべてのコントロールはこの条件に適合するので、問題はありません。

TObject からの直接の子孫となるクラスを登録することはありません。

クラスが登録されたら、FindClass に文字列を渡すことによって、型へのポインタを取得することができます。返されるクラス参照を使用してフォームを作成できます。

procedure TForm1.Button2Click(Sender: TObject);
var
  b : TForm;
  f : TFormClass;
begin
  f := TFormClass(findClass('TForm2'));
  b := f.create(self);
  b.show;
end;

これにより、RegisterClass で登録した TFrom2 型を作成します。

サンプルコード:

新規にプロジェクトを作成し、フォームを4つ追加します。合計で5つのフォームとなります。フォームにコントロールを配置しても構いませんが、この例では重要なことではありません。

最初のフォームに、TEdit と TButton を1つずつ配置します。メインフォームを除くすべてのフォームを プロジェクト(P)|オプション(O)|自動作成の対象(A) から外します。最後に、以下のコードを unit1 に貼り付けます。これによりクラス名を Edit に入力し、そのフォームを作成することができます。

unit Unit1;

interface

uses
  Unit2, Unit3, Unit4, Unit5, Windows, Messages,
  SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  RegisterClass(TForm2);
  RegisterClass(TForm3);
  RegisterClass(TForm4);
  RegisterClass(TForm5);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  f : Tformclass;
begin
  f := tformclass(findClass(edit1.text));
  with f.create(self) do
   show;
end;

    TPrinter の PixelsPerInch プロパティの設定

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

プリンタを変更する際に、フォントサイズが適切にスケールされるとは限りません。

適切なスケールを確実にするには、PrinterIndex プロパティを変更後に Font のPixelsPerInch を設定します。プリントジョブを開始するまでは変更を行なってはいけません。

2つのサンプルコード

uses Printers;

var
  MyFile: TextFile;
begin
  Printer.PrinterIndex := 2;
  AssignPrn(MyFile);
  Rewrite(MyFile);
  Printer.Canvas.Font.Name := 'Courier New';
  Printer.Canvas.Font.Style := [fsBold];
  Printer.Canvas.Font.PixelsPerInch:=
    GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY);
  Writeln(MyFile, 'Print this text');
  System.CloseFile(MyFile);
end;


uses Printers;

begin
  Printer.PrinterIndex := 2;
  Printer.BeginDoc;
  Printer.Canvas.Font.Name := 'Courier New';
  Printer.Canvas.Font.Style := [fsBold];
  Printer.Canvas.Font.PixelsPerInch:=
    GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY);
  Printer.Canvas.Textout(10, 10, 'Print this text');
  Printer.EndDoc;
end;

    StringGrid で特定の行を削除する方法

該当するバージョン:Delphi 1.0、Delphi 2.0 Delphi 3.0/Delphi 3.1, Delphi 4

Q:
StringGrid で特定の行を選択して削除することはできますか。
A:
StringGrid の行を削除するための手続きなどは用意されておりませんので、削除する場合はプログラミングして頂く必要があります。

下記の例では、ボタンが押されると現在選択されている行を一行削除します。

   procedure TForm1.Button1Click(Sender: TObject);
   var
      I,J: Integer;
   begin
      with StringGrid1 do
      begin
         for I := 1 to ColCount - 1 do
            for J := Row to RowCount - 1 do
               Cells[I, J] := Cells[I, J+1];
         if RowCount > 1 then RowCount := RowCount - 1;
      end;
   end;

    Image コンポーネントの描画内容の一部をコピーする方法

該当するバージョン:Delphi 1.0、Delphi 2.0 Delphi 3.0/Delphi 3.1, Delphi 4

Q:
Image コンポーネントの描画内容の一部をコピーするにはどのようにすればよいでしょうか。

A:
Image の一部を、別の Image にコピーするには、CopyRect を使用します。以下の例では、 Image1 の左上からマウスが押された範囲を Image2 にコピーします。

   procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
       Shift: TShiftState; X, Y: Integer);
   var
      R:   TRect;
   begin
      R.Left   := 0;
      R.Top    := 0;
      R.Right  := X;
      R.Bottom := Y;
      Image2.Canvas.CopyRect(R, Image1.Canvas, R);
   end;

    ListBox 内の文字色の変更と背景色の変更について

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
ListBox コンポーネントで選択した項目の文字や背景の色はどのように変更すればよいでしょうか。

A:
リストボックス内の項目を描画するには OnDrawItem イベントハンドラで処理を行います。 OnDrawItem イベントが発生するのは Style プロパティが lbOwnerDrawFixed か lbOwnerDrawVariable の時です。

以下の例では、選択中の項目と選択されていない項目の、背景色と文字色をそれぞれ変更します。

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  with ListBox1 do
  begin
     {選択されている項目の色の設定}
     if odSelected in State then begin
        Canvas.Brush.Color := clYellow;
        Canvas.Font.Color := clRed;
     end
     {選択されていない項目の色の設定}
     else begin
        Canvas.Brush.Color := clNavy;
        Canvas.Font.Color := clAqua;
     end;
     Canvas.FillRect(Rect);
     Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]);
  end;
end;

    TFindDialog コンポーンネントを使用して文字列の検索を行う

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TFindDialog コンポーンネントを使用して文字列の検索を行うにはどうしますか ?

A:
TFindDialog は、ユーザーがファイル内のテキストを検索するための[検索]ダイアログボックスを表示します。TFindDialg の OnFind イベント内で文字列を探すためのコードを記述します。

procedure TForm1.Button1Click(Sender: TObject);
begin
  FindDialog1.Execute;
end;

procedure TForm1.FindDialog1Find(Sender: TObject);
var
  I, J, PosReturn, SkipChars: Integer;
begin
    For I := 0 to Memo1.Lines.Count do
  begin
    PosReturn := Pos(FindDialog1.FindText,Memo1.Lines[I]);
    if PosReturn <> 0 then {見つかりました}
      begin
        Skipchars := 0;
        for J := 0 to I - 1 do
          Skipchars := Skipchars + Length(Memo1.Lines[J]);

        SkipChars := SkipChars + (I*2);
        SkipChars := SkipChars + PosReturn - 1;
        Memo1.SetFocus;
        Memo1.SelStart := SkipChars;
        Memo1.SelLength := Length(FindDialog1.FindText);
      end;
  end;

end;

    Windows のシャットダウンを感知

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Delphi で作成したアプリケーションから Windows のシャットダウンを感知してシャットダウンを防ぐことができます。

簡単な方法は、メインフォームの OnCloseQuery イベントで処理を行います。

Windows がシャットダウンする際にすべての実行中のアプリケーションにWM_QUERYENDSESSION が送られるためにこのイベントが発生します。

Windows の終了をタスクバーから起動するとこのイベントが呼ばれ、論理型の引数の CanClose に True を設定すると Windows がシャットダウンされ、False を設定するとシャットダウンされません。

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  { シャットダウンするか尋ねる }
  if MessageDlg('シャットダウン ?', mtConfirmation, mbYesNoCancel, 0) = mrYes
  then CanClose := true    { Windows のシャットダウンを行う }
  else CanClose := false;  { Windows のシャットダウンを防ぐ }
end;

    OnSetText の使用例

該当するバージョン:Delphi 1.0、Delphi 2.0 Delphi 3.0/Delphi 3.1, Delphi 4

TDBGrid に表示されている実数型項目に数字以外の値を入れた場合に出力されるエラーメッセージを処理するために OnSetText を使用できます。

実数型項目には数字以外は入力できませんが、e は入力可能です。

以下のコードは、入力された値が 0 から 9 の範囲かどうかを調べています。

0 から 9 の範囲内であればその値を設定し、0 から 9 の範囲以外の値の場合には、元の値を復元します。

DBDEMOS Country.db を使用:

  1. TTable をダブルクリック後、右ボタンのクリックで「項目の追加」ですべて追加します。
  2. Population をクリックした後オブジェクトインスペクタの OnSetTextに以下のコードを記述してください。
  3. IsDigit 関数は数字かどうかを調べます。
function IsDigit(ch: Char): Boolean;
begin
  Result := ch in ['0'..'9'];
end;

procedure TForm1.Table1PopulationSetText(Sender: TField;
  const Text: String);
var
  i, len : Integer;
  Input: array [0..9] of Char;
  Ret: Boolean;
begin
  len := Length(Text);
  StrPCopy(Input, Text);
  for i := 0 to len -1 do
  begin
    Ret := IsDigit(Input[i]);
    if (Ret = False) then begin
      ShowMessage('入力が不正です。');
      Break;
    end
    else
      Continue;
  end;
  if Ret = True then
    Sender.AsString := Text;  // 入力データが正しい場合
end;

    TEdit 上で Enter キーを押すと発生するビープ音を消すには。

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TEdit コンポーネント上で Enter キーを押すとビープ音が発生します。このビープ音を消すにはどうしたらよいでしょうか。

A:
TEdit の OnKeyPress イベントで Enter キーの処理を行いパラメータの Key に #0 を代入します。シャープ記号(#)の後に 0 から 255 までの符号なし整数定数を続けると、対応する ASCII 値の文字が表されます。

Enter キーが押されると Key には VK_RETURN が渡されて通常はビープ音が発生しますが、 #0 を指定することで Key に null を代入することとなりビープ音を抑制できます。

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = Chr(VK_RETURN)) then
    Key := #0;
end;

    実行時に TreeView にノードを追加するには

該当するバージョン:Delphi3.0/3.1、Delphi4

Q:
実行時に TreeView で選択したアイテムにノードを追加するためにはどのようにすればよいでしょうか。

A:
実行時に選択されているアイテムは、Selected プロパティで調べる事ができます。

以下の例は Popup コンポーネントを使用して、ポップアップメニューからノードの追加を行う事ができます。

  • フォーム上に TreeNode コンポーネントと Popup コンポーネントを配置します。
    Popup コンポーネントをダブルクリックしてデザイナを開き、メニュー項目を追加し、以下のように設定します。

N1: TMenuItem → Caption: 'ノードを追加’

N2: TMenuItem → Caption: '子ノードを追加’

N1,N2 の OnClick イベントに以下のように記述します。

procedure TForm1.N1Click(Sender: TObject);
var
  Node: TTreeNode;
begin
  // ノードを追加
  Node := TreeView1.Selected;
  TreeView1.Items.Add( Node,'Test1' );
end;

procedure TForm1.N2Click(Sender: TObject);
var
  Node: TTreeNode;
begin
  // 子ノードを追加
  Node := TreeView1.Selected;
  TreeView1.Items.AddChild( Node,'Test2' );
end;

    長い処理の最中に、処理を中断する方法

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
for 文等、長い処理の最中に処理を中断できるようにするには、どのようにすればよいでしょうか ?

A:
処理中に Application.ProcessMessages を記述する事でメッセージを処理し、フラグをチェックする事により、処理の中断が可能になります。

以下は Form 上に Button を2つ配置し、Button1 を押すと for 文による長い処理を開始し、Button2 を押すと処理を中断するサンプルです。

TForm には bCancel : Booleanを public 宣言し、Form の Create イベントでbCancel フラグを False に設定します。

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
begin
  for i := 0 to 5000 do
  begin
    if bCancel = True then
    begin
      bCancel := False;
      exit;
    end;
    Button1.Caption := IntToStr(i);
    Application.ProcessMessages;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  bCancel := True;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  bCancel := False;
end;

    TScrollBarのつまみの大きさを変更する方法

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TScrollBarのつまみの大きさを変更することはできますか ?

A:
Windows API の SetScrollInfo 関数を用います。TScrollInfo のメンバ nPage に、スクロール範囲に対する相対的な大きさを指定します。

var
  si: TScrollInfo;
begin
  si.cbSize := SizeOf( TScrollInfo );
  si.fMask := SIF_PAGE;
  si.nPage := 5; { Max - Minに対する相対的な大きさを指定します }
  SetScrollInfo( ScrollBar1.Handle, SB_CTL, si, True );
end;

    StringGrid で入力文字数の制限を行なう方法

該当するバージョン:Delphi 2.0 Delphi 3.0/Delphi 3.1 Delphi 4

Q:
StringGridで入力文字数の制限を行なうにはどのようにすればよいでしょうか ?

A:
StringGrid の編集用コントロールは、InplaceEditor という StringGridのプロテクトメンバです。この InplaceEditor の入力文字数を制限ることで、StringGrid の入力文字数制限を実現できます。StringGrid が編集状態になる直前の OnGetEditText イベントで、メッセージをポストします。InplaceEditorのハンドルを取得する方法によって、2通りの手法が考えられます。

方法1:Windows API 関数 GetWindow InplaceEditor にアクセスする方法

procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol,
  ARow: Integer; var Value: String);
var
  hWnd: THandle;
  maxlen: Integer;
begin
  hWnd := GetWindow( ( Sender as TStringGrid ).Handle, GW_CHILD );
  if hWnd <> 0 then begin
    { この例では、ARowを入力文字数にしています }
    maxlen := ARow;
    PostMessage(hWnd, EM_LIMITTEXT, maxlen, 0);
  end;
end;

方法2:仮のクラスを宣言してInplaceEditorにアクセスする方法

{ 宣言のあるユニット内ではそのクラスの protect メンバにアクセスできます }
type TDummy = class(TStringGrid); 
procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer; var Value: String);
var
  hWnd: THandle;
  maxlen: Integer;
begin
  if TDummy( Sender ).InplaceEditor <> nil then
  begin { この例では、ARowを入力文字数にしています }
    maxlen := ARow;
    hWnd := TDummy( Sender ).InplaceEditor.Handle;
    PostMessage( hWnd, EM_LIMITTEXT, maxlen, 0);
  end;
end; 

    StringGrid で文字を右寄せする方法 (1998/09/04)

該当するバージョン:Delphi 2.0 Delphi 3.0/Delphi 3.1 Delphi 4

Q:
StringGrid で文字を右寄せしたいのですが ?

A:
OnDrawCell イベントに処理を記述することで可能です。以下の二つの例では、カラムによって、表示形式を指定します。

1

procedure TForm1.StringGrid1DrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
var
  DRect:  TRect;
  Mode: Integer;
begin
  StringGrid1.Canvas.FillRect(Rect);

  DRect.Top := Rect.Top + 2;
  DRect.Left := Rect.Left + 2;
  DRect.Right := Rect.Right - 2;
  DRect.Bottom := Rect.Bottom - 2;
  if Col = 1 then        //右寄せ
    Mode := DT_RIGHT
  else if Col = 2 then   //左寄せ
    Mode := DT_LEFT
  else
    Mode := DT_CENTER;   //中央

  DrawText(StringGrid1.Canvas.Handle, PChar(StringGrid1.Cells[Col,Row]),
           Length(StringGrid1.Cells[Col,Row]), DRect, Mode);
end;

2

procedure TForm1.StringGrid2DrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
var
  xpos,
  Mode:  Integer;
begin
  if Col = 1 then begin       //右寄せ
    Mode := DT_RIGHT or TA_TOP;
    xpos := Rect.Right - 2;
  end
  else if Col = 2 then begin  //左寄せ
    Mode := DT_LEFT or TA_TOP;
    xpos := Rect.Left + 2;
  end
  else begin                  //中央
    Mode := TA_CENTER or TA_TOP;
    xpos := (Rect.Left + Rect.Right) div 2;
  end;
  SetTextAlign(StringGrid2.Canvas.Handle, Mode);

  ExtTextOut(StringGrid2.Canvas.Handle, xpos, Rect.Top + 2,
              ETO_CLIPPED or ETO_OPAQUE, @Rect,
              PChar(StringGrid2.Cells[Col, Row]),
              Length(StringGrid2.Cells[Col, Row]), nil);
end;

    文字列を一括置換するには (98/11/2)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
文字列を一括置換したいのですが関数はありますか ?

A:
Delphi 標準の関数では提供されておりませんが、文字列操作関数を使用して次のような関数を作成すれば実現できます。
以下は、Memo1 の内容を検索して「データベースエンジン」という文字を「BDE」に置換し、その結果を Memo2 にセットします。

function StringAllReplace(S, SearchStr, ReplaceStr: String): String;
var
  nPos,
  nLen: Integer;
  nWorkStr, nRetStr: String;
begin
  nWorkStr := S;
  nRetStr := '';
  nPos := Pos(SearchStr, nWorkStr);
  nLen := Length(SearchStr);
  while ( nPos > 0 ) do
  begin
      nRetStr := nRetStr + copy(nWorkStr,1,nPos - 1) + ReplaceStr;
      delete(nWorkStr,1,nPos + nLen - 1 );
      nPos := Pos(SearchStr, nWorkStr);
  end;
  nRetStr := nRetStr + nWorkStr;
  Result := nRetStr;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
    i: Integer;
begin
    Memo2.Clear;
    for i := 0 to Memo1.Lines.Count - 1 do
    begin
        Memo2.Lines.Add(StringAllReplace(Memo1.Lines[i],
                    'データベースエンジン', 'BDE'));
    end;
end;

    フォームのサイズを変更する時の最大値と最小値を制御するには (98/10/05)

該当するバージョン:Delphi 1.0、Delphi 2.0 Delphi 3.0/Delphi 3.1, Delphi 4

Q:
フォームをリサイズする時の最大値と最小値を設定して、サイズを制御することはできますか ?

A:
WM_GETMINMAXINFO メッセージは、ウィンドウのサイズまたは位置を変更しようとしているときに、そのウィンドウに送られます。この Windows メッセージを処理するために新しいメッセージ処理メソッド宣言を行ない、そのメソッドの中で、最大または最小トラッキングサイズを変更する処理を行ないます。
以下の例では、WMGetMinMaxInfo メソッドで ptMinTrackSize と ptMaxTrackSize メンバに値を設定します。これによってフォームの最大サイズと最小サイズの制御が可能となります。

type
  TForm1 = class(TForm)
  private
    { Private 宣言 }
    procedure WM_GetMinMaxInfo(var MSG: Tmessage);
                                message WM_GetMinMaxInfo;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.WM_GetMinMaxInfo(var MSG: Tmessage);
begin
  inherited;
  with PMinMaxInfo(MSG.LParam)^ do
  begin
    ptMinTrackSize.x := 300;
    ptMinTrackSize.y := 150;

    ptMaxTrackSize.x := 350;
    ptMaxTrackSize.y := 250;
  end;
end;

    コンポーネントパレットに独自のビットマップを表示したい (98/10/05)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
コンポーネントを作成したが、インストールするとコンポーネントパレットにはデフ ォルトのビットマップしか表示されない。コンポーネントパレットに独自のビットマ ップを表示する方法はありますか。

A:
デフォルトのビットマップではなく独自のビットマップを表示するには、リソースフ ァイルを作成します。その際、リソースファイル名はユニット名に、リソースファイ ル内のビットマップの名前はコンポーネント名にそれぞれ合わせます。

以下は、MyTool.Pas ユニットで TMyLabel コンポーネントを作成した場合の例です。

  1. イメージエディタから[ファイル|新規作成]で Delphi コンポーネントリソースファイル(.dcr)を作成します。
  2. リソースに 24 X 24 ピクセルの「ビットマップ」を追加し、名前を TMyLabel とします。
  3. 編集が終わったら、リソースファイルを MyTool.DCR という名前でユニットファイルがある場所と同じディレクトリに保存します。
  4. コンポーネントをインストールすると、コンポーネントパレットにリソースファイルで指定したビットマップが表示されます。

    Delphi4で作成したプログラムをタクスバーに表示させない方法はありますか ? (98/12/2)

該当するバージョン:Delphi 3.0/Delphi 3.1 Delphi 4

Q:
Delphi4で作成したプログラムをタクスバーに表示させない方法はありますか ?

A:
プロジェクトソースを以下のように変更していただければ、タスクバーに表示しないようになります。
(画面上にFormを表示させると、タスクバーにプログラムが表示されるようになります。)

    program Project1;

    uses
    Forms,
    Unit1 in 'Unit1.pas' {Form1};

    {$R *.RES}

    begin
      Application.Initialize;
      Application.ShowMainForm := False; //この行を追加する。
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end.

    TPrinterを使用し印刷する時に用紙サイズを変更するには、どのように行えば良いのでしょうか ? (99/2/3)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TPrinterを使用し印刷する時に用紙サイズを変更するには、どのように行えば 良いのでしょうか ?

A:
プリンタの用紙サイズなどを変更する場合には、DEVMODE構造体の内容を変更する事により可能になります。
下のサンプルコードを参考にしてください。

*Printer変数を使用していますので、USESには、PRINTERSを追加してください。

** カスタムサイズの設定方法についてはコメント行にてありますので、カスタムサイズを行う場合には、LEGAL を設定している部分を全てコメントに変更しカスタムサイズの部分を実行するようにしてください。

procedure TForm1.Button1Click(Sender: TObject);
var
   Device : array[0..255] of Char;
   Driver : array[0..255] of Char;
   Port   : array[0..255] of Char;
   hDMode : THandle;
   PDMode : PDEVMODE;
begin
   Printer.GetPrinter(Device,Driver,Port,hDMode);
   if hDMode <> 0 then
   begin
      pDMode := GlobalLock(hDMode);
      if pDMode <> nil then
      begin
//    legalを設定する場合
         pDMode^.dmFields := pDMode^.dmFields or dm_PaperSize;
         pDMode^.dmPaperSize := DMPAPER_LEGAL;

//    カスタムサイズの設定をする場合
//         pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or
//                                                 DM_PAPERWIDTH or
//                                                 DM_PAPERLENGTH;
//         pDMode^.dmPaperSize := DMPAPER_USER;
//         pDMode^.dmPaperWidth := 100;
//         pDMode^.dmPaperLength := 100;

         Globalunlock(hDMode);
      end;
   end;

//設定されている内容をPrinterSetupDialogで確認する

   printersetupdialog1.Execute;

//印字テスト
   Printer.BeginDoc;
   Printer.Canvas.TextOut(100,100,'Test 1');
   Printer.EndDoc;

end;

    TList.Sort メソッドの使い方 (99/03/04)

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TList クラスを使ってデータを管理してます。このデータをソートしたいのですが、TList.Sort メソッドのヘルプを見ても使い方がわかりません。
TStringList.Sort のように使えないのでしょうか ?

A:
TStringList.Sort は扱うデータがあらかじめ文字列だと解っていますので、そのデータを比較する方法もあらかじめ解ります。 しかしながら、TList クラスは汎用的なリストですので、そのデータや、ソートの方法をプログラム側で管理しなければなりません。

TList.Sort メソッドのパラメータはソートにつかう大小比較関数を渡します。
TList クラスはその関数の比較結果を元にリストを並び替えます。

以下のようなレコードを TList が保持している場合には、

type
  PStaff = ^Staff;
  Staff = record
    Age: integer;
    Name: ShortString;
  end;

以下のような関数を定義します。 この関数が要素の大小を比較します。

function StaffSortCompare(Item1, Item2: Pointer): Integer;
begin
  Result := PStaff(Item1)^.Age - PStaff(Item2)^.Age;
end;

そして以下のように呼び出します。

procedure TForm1.Button1Click(Sender: TObject);
begin
  StaffList.Sort(StaffSortCompare);
end;

    プリンタの出力ポートを変更するには (99/03/04)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
プログラム中でプリンタの出力ポートを変更することはできますか ?

A:
TPrinter クラスの SetPrinter メソッドを使います。
以下のサンプルでは、出力先をファイルに変更しています。

procedure TForm1.Button1Click(Sender: TObject);
var  pDevice : pChar;  pDriver : pChar;  pPort   : pChar;  hDMode : THandle;
  PDMode : PDEVMODE;
begin
  if PrintDialog1.Execute
  then
  begin
    GetMem(pDevice, cchDeviceName);
    GetMem(pDriver, MAX_PATH);
    GetMem(pPort, MAX_PATH);
    Printer.GetPrinter(pDevice, pDriver, pPort, hDMode);
    Printer.SetPrinter(pDevice, PDriver, 'FILE:', hDMode);
    FreeMem(pDevice, cchDeviceName);
    FreeMem(pDriver, MAX_PATH);
    FreeMem(pPort, MAX_PATH);
    Printer.BeginDoc;
    Printer.Canvas.TextOut(100, 100, 'Delphi Is RAD!');
    Printer.EndDoc;
  end;
end;

    数値を3ケタごとに区切って表示したい (99/03/04)

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
数値を3ケタごとにカンマで区切って表示したいのですが, 簡単な方法はないでしょうか ?

A:
以下のような記述で期待どうりの結果を得られます。

i := 12345678;
Memo1.Lines.Add(FormatFloat('0,', i));

注意: 実際に使われる区切り文字は, システムの環境設定に影響されます。
[コントロールパネル | 地域 | 数値 | 桁区切り記号] を確認してください。

    Page Controlの中の特定のPageを選択できないようにするには、どのように行えばよいのでしょうか ? (99/03/04)

該当するバージョン:Delphi 3.0/Delphi 3.1 Delphi 4

Q:
Page Controlの中の特定のPageを選択できないようにするには、どのように行えばよいのでしょうか ?

A:
PageControlのOnChangingイベントで、クリックされたPageであった場合に、AllowChangeをFalseにセットする事で可能となります。

マウスでクリックされたPageを知るには、Windows APIのGetCursorPos、TabCtrl_HitTestを使用します。

以下のサンプルプログラムを参考にしてください。
サンプルではTabSheet3をクリックされた場合、無効になります。

* サンプルでは、USESにCommCtrlを追加してください。

    procedure TForm1.PageControl1Changing(Sender: TObject;
      var AllowChange: Boolean);
    var
       Info : TTCHitTestInfo;
       Index : Integer;
    begin
       with Info do
       begin
            GetCursorPos(pt);
            pt := PageControl1.ScreenToClient(pt);
            flags := TCHT_ONITEM;
       end;
       index := TabCtrl_HitTest(PageControl1.Handle, @info);
       AllowChange := Index <> 2;
    end;

    プログラムでカラー印刷がしたいのですが (99/03/04)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
プログラムでカラー印刷がしたいのですが

A:
カラープリンタを使用しカラー印刷を行うには、Tprinterを使用し、プリンタドライバのDevMode構造体の内容を変更する事によって可能となります。
以下のサンプルを参考にしてください。

*USESにPrintersを追加します。

procedure TForm1.Button1Click(Sender: TObject);
var
  Device : array[0..255] of char;
  Driver : array[0..255] of char;
  Port   : array[0..255] of char;
  hDMode : THandle;
  PDMode : PDEVMODE;
begin
  with Printer do
  begin
       PrinterIndex := PrinterIndex;
       GetPrinter(Device, Driver, Port, hDMode);
       if hDMode <> 0 then
       begin
            pDMode := GlobalLock(hDMode);
            if pDMode <> nil then
            begin
                 pDMode.dmFields := pDMode.dmFields or dm_Color;
                 pDMode.dmColor := DMCOLOR_COLOR;
                 GlobalUnlock(hDMode);
            end;
       end;
       PrinterIndex := PrinterIndex;
       BeginDoc;
          Canvas.Font.Color := clRed;
          Canvas.TextOut(100,100, 'Red As A Rose!');
       EndDoc;
  end;
end;

    マウスがホイール機能を持っているかどうかを判断するには ? (99/4/2)

該当するバージョン:Delphi4

Q:
実行環境のマウスがホイール機能を持っているかどうかを判断するにはどうしたらいいでしょうか ?

A:
Delphi 4 で追加された機能として, 現在のマウスの状態を保持するグローバル変数"Mouse" が用意されています。

"Mouse" 変数 の WheelPresent プロパティが, 実行環境において,ホイール機能が提供されているかどうかの判別に使えます。

そのほかの機能につきましては, TMouse オブジェクトのヘルプを参照してください。

    フォームからアンドックしたツールバーがALT-F4で消えてしまいます。消えないようにするには、どのようにしたら良いのでしょうか ? (99/4/2)

該当するバージョン:Delphi4

Q:
フォームからアンドックしたツールバーがALT-F4で消えてしまいます。消えないようにするには、どのようにしたら良いのでしょうか ?

A:
ツールバーなどをフローティングウィンドウ状態にすると、一時的なコントロールが作成され、そのコントロールにドッキングされます。そのコントロールは、TToolBarのFloatingDockSiteClass プロパティに指定されているクラスによって作成されます。
通常は、TToolDockFormになっていますが、そのクラスを派生させたクラスを指定し、フォームを終了する前にフローティングウィンドウ状態のツールバーを終了できないようにする処理を加えます。
派生させたクラスでは、終了できないようにする為に以下の処理を行います。

  1. Createをオーバーライドし、BorderIconsプロパティを設定し、タイトルバーのアイコンから終了できないようにアイコンをなしに設定する。
  2. ALT-F4時にも終了しないように、DoCloseをオーバーライドし、ActionをcaNoneに設定する。

これにより、フローティングウィンドウ状態のツールバーを終了することができない状態になります。以下のサンプルを参考にしていただきたいと思います。

type
  TTESTDockForm = class(TToolDockForm)
    Constructor Create(AOwner:TComponent); override;
    procedure DoClose( Var Action : TCloseAction) ; override;
  end;
  TForm1 = class(TForm)
    ToolBar1: TToolBar;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

Constructor TTESTDockForm.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  BorderIcons := [];
end;
procedure TTESTDockForm.DoClose( Var Action : TCloseAction);
begin
  Action := caNone;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i : integer;
begin
  for i := 0 to ComponentCount -1 do
  begin
      if Components[i] is TToolBar then
          TToolBar(Components[i]).FloatingDockSiteClass := TTESTDockForm;
  end;
end;

    ListView の項目をドラッグしてもフォーム上でドラッグイメージが消えてしまう (99/5/12)

該当するバージョン:Delphi 3.0/Delphi 3.1 Delphi 4

Q:
ListView の項目をドラッグ&ドロップできるようにしているのですが,カーソルがフォームやボタンなどの他のコントロール上にくると, ドラッグイメージが見えなくなってしまいます。 他のコントロール上でも, ドラッグイメージを表示しておきたいのですが、何かいい方法はないでしょうか ?

A:
ControlStyle プロパティに csDisplayDragImage を追加してください。
このプロパティはコントロールの各種属性を管理するのに使用しています。 以下のコードではフォームの ControlStyle を変更して, ドラッグイメージをフォーム上でも表示できるようにしています。 ボタンやメモなどの他のコントロールも同様に対応できます。

procedure TForm1.FormCreate(Sender: TObject);
begin
  ControlStyle := ControlStyle + [csDisplayDragImage];
end;

    TEdit をプログラムで動的に作成しているのですが表示されません (99/5/12)

該当するバージョン:Delphi 1.0,Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TEdit をプログラムで動的に作成しているのですが, Visible プロパティを変更しても表示されません。 何故でしょうか ?

A:
TEdit のように TControl から派生したクラスは, 見た目上の親になるコントロールが指定されていない場合, 画面上に表示されません。
見た目上の親を指定するためには Parent プロパティを設定します。
以下のコードは, 動的に作成した TEdit を Panle1 の見た目上の子のコントロールとして表示します。

procedure TForm1.Button1Click(Sender: TObject);
begin
  E := TEdit.Create(Self);
  E.Left := 10;
  E.Top := 10;
  E.Parent := Panel1;
end;

    TrackBarの移動部分の白い部分を線で表示するのは、どのように行えば良いのでしょうか ? (99/5/12)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
TrackBarの移動部分の白い部分を線で表示するのは、どのように行えば良いのでしょうか ?

A:
CreateParamsをoverrideする事により実現しています。
TTrackbarコンポーネントを作成する際のparams スタイルから TBS_ENABLESELRANGEフラグをクリアする事で白い部分が線で表示するように変わります。
以下のサンプルを参考にしてください。

※フラグの詳細説明は、Windowsのドキュメントを参考にしてください。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  CommCtrl, ComCtrls, StdCtrls;

type
 TMyTrackBar = class(TTrackBar)
       procedure CreateParams(var Params: TCreateParams); override;
end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    TrackBar2: TTrackBar;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;
  MyTrackbar : TMyTrackbar;
implementation

{$R *.DFM}
procedure TMyTrackBar.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := Params.Style and not TBS_ENABLESELRANGE;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyTrackBar := TMyTrackbar.Create(Form1);
  MyTrackbar.Parent := Form1;
  MyTrackbar.Left := 100;
  MyTrackbar.Top := 100;
  MyTrackbar.Width := 150;
  MyTrackbar.Height := 45;
  MyTrackBar.Visible := true;
end;

end.

    Delphi 4 統合環境ライクなメニューバー (99/6/4)

該当するバージョン:Delphi4

Q:
Delphi 4 の統合環境で使っているような, ツールバー上にメニューを載せたコントロールを使用したいのですが, このようなコンポーネントは用意されていないのでしょうか ?

A:
標準では用意されておりませんが, TMenubarComponent (Created 10/13/98, Size 954 bytes)にて, コンポーネントを公開しております。
このコンポーネントを使うには, MenuBar.zip ファイルをダウンロード後, ツールを使って解凍(.ZIP 形式にて圧縮されております)し, 展開された MenuBar.pas を [コンポーネント | コンポーネントのインストール]からインストールしてください。

このコンポーネントは ToolBar コンポーネントから派生していて, 以下の2つのプロパティが追加されております。

   property Menu: TMainMenu;

メニューバーに表示されるメニューを関連付けます。
MenuBar コンポーネントは, このプロパティが設定された時点のみ, メニューバーに表示されるボタンを設定します。 これは, その後, 関連付けられたメニューに項目の追加/削除などがあっても, 自動的には, それらの変更は反映されないことを意味します。 そのような場合には, 明示的に Menu プロパティの設定をやり直して, 変更が反映されるようにしてください。

Form.Menu プロパティにメニューが設定されている場合, フォーム自身が持つメニューと, メニューバーの持つメニューボタンが縦に並んで表示されます。 このような場合には Form.Menu プロパティを空にしてください。

   type
     TEdgeBorder = (ebLeft, ebTop, ebRight, ebBottom);
     TEdgeBorders = set of TEdgeBorder;
   property EdgeBorders: TEdgeBorders;

メニューバーに表示されるメニューボタンの境界の外観を定義します。
詳細は TToolWindow.EdgeBorders のヘルプを参照してください。