パネル系コンポーネントの不具合対処TipDelphi のフォームはダイアログボックスと良く似た動きをしますが、矢印キーを 使ってフォーカスを移動するときに重大な不具合が有ります Windows のダイアログではフォーカスの移動先がグループボックスの場合、グループボックス自体にはフォーカスは移動せず、グループボックスの「中」のコントロールにフォーカスが移動します。 ところが Delphi のフォームの場合は、移動先がパネル系/グループボックス系のコントロールの場合、パネルやグループボックスそのものにフォーカスが移動してしまいます。以下の図を見てください。フォーム上には Button コントロールと RadioGroup コントロールが有り、Button コントロールにフォーカスが有ります。
この状態で矢印キーを押すと、下図のようにフォーカスがどこに有るか判らない不思議な状態になってしまいます。
この問題を回避するには、パネル系/グループボックス系のコントロールの OnEnter イベントハンドラに、以下のようにコードを書いておく必要があります。 type TWinControlDummy = class(TWinControl); procedure TForm1.RadioGroup1Enter(Sender: TObject); var p: TWinControlDummy; begin if ActiveControl = Sender then begin p := TWinControlDummy(ActiveControl.Parent); if p <> Nil then ActiveControl := p.FindNextControl(ActiveControl, True, True, True); end; end; 解説この問題はけっこう根が深いバグです。VCL はフォーカスの移動を FindNectControl メソッドを使って行いますが、FindNextControl は CanFocus メソッドが False を返すようなコントロールを選ばないのでパネル系コントロールの CanFocus が False なら問題ありません。実際パネル系コンポーネントはマウスでクリックしてもフォーカスを受け取らないので、CanFocus が False を返しても良いように思えます。しかし、TWinControl の CanFocus は Visible で Enabled な場合 True を返すので、パネル系のコントロールも CanFocus が True になってしまいます。 Delphi 4 までは CanFocus メソッドは virtual/dynamic では無かったので変更できませんでした。しかし Delphi 5 以降は dynamic になったので、コントロール側で自由に実装を変更できるようになりました。しかし残念ながら Delphi 6 でも未だにパネル系コントロールは Visible and Enabled を返します。 Tip のコードを説明します。 コントロールはフォーカスを受け取ると OnEnter イベントが起きますが、パネル系やグループ系など、自分の中にコントロールを含む事ができるコントロールでは、自分の子コントロールにフォーカスが移ったときも OnEnter イベントが発生します。従って、本当に自分にフォーカスが来ているかどうかは ActiveControl プロパティ でチェックしなければなりません。 TWinControl の FindNextControl メソッドは配下のコントロールのタブ順のリストを作り、指定されたコントロールの「次」のコントロールを探してくれます。FindNextControl は指定されたコントロールを起点にして指定された方向にリストを探索し、条件に合う最初のコントロールを返します。 function FindNextControl(CurControl: TWinControl; GoForward, CheckTabStop, CheckParent: Boolean): TWinControl; パラメータは上の通りですが、GoForward は探索の向きを表し True は次(Forward)、False は前(Backword)を指定します。CheckTabStop と CheckParent は隣のコントロールを選ぶときの条件で、チェックは以下のように行われます。
Tip のコード(OnEnter のイベントハンドラ)はまず、自分にフォーカスが移りつつあるかを確かめます。もしそうなら、自分の親のFindNextControlメソッドを使って、自分と同じ親お持ち、TabStop=True なコントロールにフォーカスをセットしなおしてもらいます。 |