Delphi Tips 
-----------------------------

0235  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/06 西坂良幸 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/11 K.Takaoka 編集
エディットコントロールにポップアップウィンドウをつけたい

エディットコントロールにボタンをつけた、コンボボックスもどきは、カスタムコントロールでよく見かけます。ボタンを押すと小ウィンドウが開くヤツです。これはどのように作るのでしょうか。

このような小ウィンドウをインプレースコントロールと呼びます。
ポイントは、小ウィンドウの親をコントロールにすることと、独自のフォーカスを与えないことです。これさえ理解できれば後は、小ウィンドウのVisbleの切り替えで開いたり閉じたりします。

ここでは、プロパティを受け渡すことを無視し、ただ開閉だけをやってみます。(マウス右ボタンで開く)

//  定義部
  TxEdit = class;

  // インプレースコントロール ここではリストボックス
  TinPlaceList = class(TListbox)
  private
    FEdit: TxEdit;
  protected
    procedure CreateWnd; override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  public
    constructor CreateList(AOwner: TComponent; Edit: TxEdit);
  end;

  // ここでは、TEditから継承する
  TxEdit = class(TEdit)
  private
    FInplaceList:TListbox;
  protected
    procedure Mousedown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent);override;
    destructor Destroy;override;
    procedure DropDown;
  end;

// 実装部

//コンストラクタでコントロールに接続させる
constructor TInplaceList.CreateList(AOwner: TComponent; Edit: TxEdit);
begin
  inherited Create(AOwner);
  // 小ウィンドウに親のポインタを持たせて接続する
  FEdit := TxEdit(Edit);
  Visible := false;
end;

// インプレースコントロールの生成とフォーカス制御
procedure TInplaceList.CreateWnd;
begin
  inherited CreateWnd;
   //親の変更を行う
  if not (csDesigning in ComponentState) then
    Windows.SetParent(Handle, 0);
  //独自のフォカスメッセージを避ける
  CallWindowProc(DefWndProc, Handle, WM_SETFOCUS, 0, 0);
end;

//とりあえずマウス(左右)で閉じることにする
procedure TInplaceList.MouseUp(Button: TMouseButton; Shift: TShiftState;
    X, Y: Integer);
begin
  inherited MouseUp(Button, Shift, X, Y);
  if Button = mbLeft then
  begin
    // プロパティの受け渡しをここらで行う
    Hide;
  end;
  if Button = mbRight then
    Hide;
end;

// コンストラクタで、インプレースコントロールを生成
constructor TxEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FInplaceList := TInplaceList.CreateList(Self, Self);
  with FInplaceList do
  begin
    Parent := Self;
    TabStop := false;
    Visible := false;
    Top := FInplaceList.Top + Self.Height;
  end;
end;

// デストラクタで念のため明示的に解放する
destructor TxEdit.Destroy;
begin
  FInplaceList.free;
  inherited Destroy;
end;

// ドロップダウンリストの開閉のメソッドを作成する
procedure TxEdit.DropDown;
var
  xyPos: TPoint;
begin
  if (FInplaceList <> nil) and not FInplaceList.Visible then
  with FInplaceList do
  begin
    xyPos := Self.ClientToScreen(Point(0 + Self.Width - Width,  Self.Height));
    SetWindowPos(Handle, 0, xyPos.X, xyPos.Y, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE);
    Windows.SetFocus(Handle);
    Visible := not Visible;
    // プロパティの受け渡しをここらで行う
  end;
  Invalidate;
end;

// マウス右ボタンで開く
procedure TxEdit.Mousedown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  if Button = mbRight then
    DropDown;
  inherited Mousedown(Button, Shift, X, Y);
end;

TListBoxのかわりに、何でも使えます。TPanelなら、電卓、カレンダなどになりますね。TGridでもいいですね。
実際にカスタムコントロールを作るときは
・やはりボタンをつける
・キーボード入力にも対応させる
・必要なプロパティの受け渡しを行う
・ドロップダウンなどイベントを記述する
・ロストフォーカスで開きっぱなしにしない
などが必要でしょうか。

参照: [Delphi-ML:40241] <コンポーネント開発> <コンポーネント > <Standard>

[新規作成] [最新の情報に更新]

How To
Lounge
KeyWords


Tips
Delphi
Home
Osamu Takeuchi osamu@big.or.jp