Panelにフォーカスを持たせ、キー入力させるには?

解決


take  2012-07-24 01:10:32  No: 42663

今更な質問で恐縮ですが
環境はWindowsXP + Delphi5

TPanelからの派生クラスを作成してキー入力をさせようとしています。
作成したクラスをマウスでクリックした後、カーソルの上下左右を処理したいのですが
うまくいきません。

マウスクリックイベントで処理した後
キー入力イベントを使おうとすると、イベントが発生しないため
KeyPreviewをTrueにしたFormのキー入力イベントを受けてPanelに渡しました。
ここまでは動作するのですが

フォーム上のButtonをクリックしてフォーカスをボタンに移動した後に
作成したクラスをマウスでクリックした後は
ボタンにフォーカスがあるため最初のキー入力イベントが来ません。

かといってマウスクリックイベント内で
自分自身(TPanel)にSetFocusすると
今度はフォームも含め、何もイベントが発生しなくなります。

根本的に考え方が間違っているのでしょうか?


monaa  2012-07-24 02:13:56  No: 42664

的外れかも知れませんが、
自作コントロールにカーソルを表示するサンプルを作ってみました。
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.


take  2012-07-24 02:17:11  No: 42665

monaa様、ありがとうございます。
ちょっと今、試す環境がないので明日試します。


初心者  2012-07-24 18:18:13  No: 42666

ApplicationEvents使ってOnmessageイベントで取得したらダメなのかな?


take  2012-07-24 18:23:22  No: 42667

>的外れかも知れませんが、
>自作コントロールにカーソルを表示するサンプルを作ってみました。

的外れどころか、まさにこれです!!
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;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加