エディットコントロールにポップアップウィンドウをつけたい
|
エディットコントロールにボタンをつけた、コンボボックスもどきは、カスタムコントロールでよく見かけます。ボタンを押すと小ウィンドウが開くヤツです。これはどのように作るのでしょうか。
このような小ウィンドウをインプレースコントロールと呼びます。
ポイントは、小ウィンドウの親をコントロールにすることと、独自のフォーカスを与えないことです。これさえ理解できれば後は、小ウィンドウの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でもいいですね。
実際にカスタムコントロールを作るときは
・やはりボタンをつける
・キーボード入力にも対応させる
・必要なプロパティの受け渡しを行う
・ドロップダウンなどイベントを記述する
・ロストフォーカスで開きっぱなしにしない
などが必要でしょうか。
|
|