アクセラレータキーの反応

解決


ofZ  2008-02-08 05:12:43  No: 29707

フォームにTSpeedButton配置×2
キャプションをそれぞれ、以下として
Caption := hoge1(&1)
Caption := hoge2(&2)
ボタンクリックイベントで、キャプションを表示するようにする
ShowMessage(TSpeedButton(Sender).Caption);

これで、テンキーとかで「1」「2」を叩けば、「hoge1(&1)」「hoge2(&2)」が
メッセージで表示されます。

この機能はOKとして、特定のコンテナクラス(TPanelとか)に乗っている
コンポーネントは、反応しないようにするには、どうしたらいいのでしょう?

無反応にしたいパネルで、何かのメッセージを無効化しておけばいいんでしょうか?
もっとラクチンな方法があれば、教えてください。


Fusa  2008-02-08 06:32:23  No: 29708

特定のコンテナに乗っているものだけ
&1を解除する。

とかいうのではだめでしょうか…
文字列置き換えが楽じゃなさそうか。


KHE00221  2008-02-08 06:44:26  No: 29709

そもそもアクセラレータキーを必要としないのに &1 とかを設定する
理由はなんですか?

ActionList に設定すればそちらが優先されるので ActionList に設定したらどうですか? 

話は変わるけど・・・

ここの人かな?
http://okapony.hp.infoseek.co.jp/


ofZ  2008-02-08 17:25:46  No: 29710

> 特定のコンテナに乗っているものだけ
> &1を解除する。
それ、めんどくさそうだから、最終手段で(^^ゞ

> そもそもアクセラレータキーを必要としないのに &1 とかを設定する
> 理由はなんですか?
TActionで作成していて、TMenuItemでもそのまま使うから。

というのも、TAction の実行履歴を10個のTSpeedButtonで実現していて、
それらは、Actionを割り当てるだけにしているから。
TActionのCaptionを(&A)抜きにして、TMenuItemでは手動でつけてもいいけど、
ちょっと多すぎて、イヤになってます。

> ここの人かな?
???なぜに???
んまぁ・・・確かに私は、KHE00221さんのPas2HTMLを使っています。
ありがとうございます。
便利に使わせていただきました。
・・・と、こんなところでお礼申し上げます。


ofZ  2008-02-08 20:29:26  No: 29711

方法1:カスタムコンポをつくって、そこに乗せる

  TMyPanel=class(TPanel)
    procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  end;

procedure TMyPanel.CMDialogChar(var Message: TCMDialogChar);
begin
  //もみ消し
end;

方法2:コンテナクラス(今回の場合 TPanel)のメッセージをフックして
やっぱり、CM_DIALOGCHAR をもみ消す

方法3:Captionを変更する(Fusaさんの方法)
今回、10件程度の履歴を表示するコントロールなので、
それほどめんどくさくなかったです。
めんどくさいなんて言ってすいません >Fusaさん

Menus.pas の宣言を利用する
> cHotkeyPrefix := '&';

各履歴用SpeedButtonは、配列に格納済みとして
for i := 0 to 9 do begin
  SpeedButton[i].Action := 履歴のAction[i];
  SpeedButton[i].Caption := 自作cHotkeyPrefixを取り除く関数(SpeedButton[i].Caption);
end;

KeyDownとかを、もっと追いかけたら、もっと少しいい方法があるかもしれないけど
とりあえずは、これだけしか思いつかない。
方法1、2は、他に影響でるかもしれないので、とりあえず方法3で乗り切ってみます。

KHE00221 さんが、すばらしい技を披露してくれそうな予感がしますが、
とりあえずは、〆ます。

それではみなさん、ごきげんよう


KHE00221  2008-02-08 21:20:10  No: 29712

コンポーネント化しなくても

  TPanel = class(ExtCtrls.TPanel)
     procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  end;

  TForm1 = class(TForm1)
  end;

var
  Form1 : TForm1;

implementation

procedure TPanel.CMDialogChar(var Message: TCMDialogChar);
begin
    if Handle <> Form1.Panel1.Handle then inherited;   
end;

とやれば Panel1 に メッセージは届かなくなるよ?


Fusa  2008-02-08 22:04:41  No: 29713

> それほどめんどくさくなかったです。
> めんどくさいなんて言ってすいません >Fusaさん

いや、俺もたぶんめんどくさく感じてしまうので
あやまんなくてもいいっす。
質問せずに誰にも聞かずに、めんどくさい方法を選択するよりも
聞いてエレガントな解決方法を探るなんて、いいことじゃないですか。

CMDialogCharが流れるのですね。
勉強になってます。

方法2のTPanelのメッセージフックって、どうやるんでしたっけ?
Formのwndproc置き換えならよくやったのですが。

自分だったら
再利用考えなければ、ApplicationOnMessageで処理する
手もあるかな、と思います。
CM_系のメッセージは流れるのかな?

KHE00221さん
IDEにはPanel1 TPanelとして扱わせて
コード上ではキャストしてメッセージ横取り...

あいかわらずの冴えっぷり。すごいですね。


ofZ  2008-02-13 00:44:01  No: 29714

KHE00221さん
> コンポーネント化しなくても
毎度毎度、KHE00221さんのレスは、お勉強になります。
数枚のパネルが乗っているフォームなので、特定のパネルに対してのみ
継承したコンポーネントとして利用できないのは、いまいちなんですが、
まとめてコンポーネントの動作を差し替えしたいような場合に使える
とても便利な技かと思います。
いつか使える日がくると信じて、メモしておきました。

Fusaさん
> 方法2のTPanelのメッセージフックって、どうやるんでしたっけ?
> Formのwndproc置き換えならよくやったのですが。
Delphi2の頃からのコンポーネントをそのまま使っているだけなのですが、
このようにメッセージ処理を差し替えています。
OldWndProc := GetWindowLong(Panel1.Handle, GWL_WNDPROC);
SetWindowLong(Panel1.Handle, GWL_WNDPROC, Longint(NewWndProc));

今、Delphi5を使っており、TControl.WindowProc を差し替えるだけで
同じコトが実現できますが、まぁ、コンポーネントを書き換えるのも
めんどくさくて(めんどくさいばっかり)、これをそのまま使ってます。

んで、方法2を今風に書いてみるとこんな感じ

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    OldWndProc: TWndMethod;
    procedure NewWndProc(var Message: TMessage);
  end;

procedure TForm1.NewWndProc(var Message: TMessage);
begin
  if Message.Msg <> CM_DIALOGCHAR then begin
    OldWndProc(Message);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  OldWndProc := Panel1.WindowProc;
  Panel1.WindowProc := NewWndProc;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Panel1.WindowProc := OldWndProc;
end;

cHotkeyPrefixを取り除く関数を作るのと、どっちが楽かっていうと、
ホントは、こっちが楽だったりする。


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

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






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