今更な質問で恐縮ですが
環境はWindowsXP + Delphi5
TPanelからの派生クラスを作成してキー入力をさせようとしています。
作成したクラスをマウスでクリックした後、カーソルの上下左右を処理したいのですが
うまくいきません。
マウスクリックイベントで処理した後
キー入力イベントを使おうとすると、イベントが発生しないため
KeyPreviewをTrueにしたFormのキー入力イベントを受けてPanelに渡しました。
ここまでは動作するのですが
フォーム上のButtonをクリックしてフォーカスをボタンに移動した後に
作成したクラスをマウスでクリックした後は
ボタンにフォーカスがあるため最初のキー入力イベントが来ません。
かといってマウスクリックイベント内で
自分自身(TPanel)にSetFocusすると
今度はフォームも含め、何もイベントが発生しなくなります。
根本的に考え方が間違っているのでしょうか?
的外れかも知れませんが、
自作コントロールにカーソルを表示するサンプルを作ってみました。
KeyPreviewはFalseで確認しています。
抜き出しなので余計なものがついているかもしれません。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, imm;
type
TFePanel = class(TPanel)
private
fCaret:TPoint;
constructor Create(AOwner: TComponent); override;
procedure MoveCaret(x,y:Integer);
procedure SetIMECOMPOSITION;
procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure CMWantSpecialKey(var Message: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
FePanel1 : TFePanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TFePanel }
procedure TFePanel.CMWantSpecialKey(var Message: TCMWantSpecialKey);
begin
inherited;
Message.Result := 1;
end;
constructor TFePanel.Create(AOwner: TComponent);
begin
inherited;
fCaret := Point(0,0);
end;
procedure TFePanel.MoveCaret(x, y: Integer);
begin
fCaret := Point(x+fCaret.X,y+fCaret.Y);
SetCaretPos(fCaret.x,fCaret.Y);
SetIMECOMPOSITION;
end;
procedure TFePanel.SetIMECOMPOSITION;
var
cf: TCompositionForm;
begin
cf.dwStyle := CFS_POINT;
cf.ptCurrentPos := fCaret;
ImmSetCompositionWindow(ImmGetContext(Handle), @cf);
end;
procedure TFePanel.WMKeyDown(var Message: TWMKeyDown);
begin
inherited;
case Message.CharCode of
VK_UP : MoveCaret(0,-10);
VK_DOWN : MoveCaret(0, 10);
VK_LEFT : MoveCaret(-10,0);
VK_RIGHT : MoveCaret( 10,0);
end;
end;
procedure TFePanel.WMKillFocus(var Message: TWMKillFocus);
begin
inherited;
DestroyCaret;
end;
procedure TFePanel.WMLButtonDown(var Message: TWMLButtonDown);
begin
inherited;
fCaret := Point(Message.XPos,Message.YPos);
SetFocus;
MoveCaret(0,0);
end;
procedure TFePanel.WMSetFocus(var Message: TWMSetFocus);
begin
inherited;
CreateCaret(Handle,0,10,10);
ShowCaret(Handle);
MoveCaret(0,0);
end;
{TForm1}
procedure TForm1.FormCreate(Sender: TObject);
begin
FePanel1 := TFePanel.Create(Self);
FePanel1.Parent := Self;
FePanel1.SetBounds(10,100,200,200);
end;
end.
monaa様、ありがとうございます。
ちょっと今、試す環境がないので明日試します。
ApplicationEvents使ってOnmessageイベントで取得したらダメなのかな?
>的外れかも知れませんが、
>自作コントロールにカーソルを表示するサンプルを作ってみました。
的外れどころか、まさにこれです!!
TPanelのフォーカスが正常に機能せずに悩んでいた件が、これで解決しました
必要な部分だけ抜粋してフォーカスを正しく処理できる
TPanelを作って見ました。
これで、マウス入力やキー入力、フォーカス取得、破棄イベントが
正しく発生することが確認できました。
ありがとうございました。
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls,imm, StdCtrls;
type
TPanelFocuse = class(TPanel)
private
FFocused : Boolean; // True : フォーカスあり
procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure CMWantSpecialKey(var Message: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
public
// イベントの再定義
property OnKeyDown;
property OnKeyUp;
property OnKeyPress;
end;
implementation
{ TPanelFocuse }
procedure TPanelFocuse.CMWantSpecialKey(var Message: TCMWantSpecialKey);
begin
inherited;
if FFocused then begin // 自分にフォーカスがある場合
Message.Result := 1; // キー入力を有効に
end;
end;
procedure TPanelFocuse.WMKillFocus(var Message: TWMKillFocus);
begin
inherited;
FFocused := False; // フォーカスを消失
end;
procedure TPanelFocuse.WMLButtonDown(var Message: TWMLButtonDown);
begin
inherited;
SetFocus; // フォーカスを有効
FFocused := True;
end;
ツイート | ![]() |