TOpenDialog上でキー押下を検出するには?(その2)

解決


まこと  2010-07-05 06:41:42  No: 38748

https://www.petitmonte.com/bbs/answers?question_id=5715

いつもお世話になります。
タイトルの件について、リンク先を基に、OpenDialog上で「Alt + C」を押した
とき、ある動作をさせていたのですが、問題が生じてしまいました。

・Alt + Cを押したときの動作の内容
  TOpenDialog上に自分でコンボボックスを追加しており、Alt + C
  が押されたとき、そのコンボボックスにフォーカスを移動させると
  いうもの。
  (テキストエディタなどでよくある、文字コード判別のコンボボックス
  のようなものと考えていただければと思います。)

・問題点
  Alt + Cを押したとき、Windowsのサウンドを有効にしていたときに、
  Beep音(のような音)が出てしまう。

・今まで試していた方法
  CallNextHookExを呼び出さなければ音はならない。
  でも、↓ここを見ると、他のソフトの動作に悪影響を与える可能性がある様子。
  http://msdn.microsoft.com/ja-jp/library/cc429591.aspx
  ↓ここを見ると、HC_Skipなどというそれらしい識別子を利用している。
    この辺を使うのかも知れないが、使い方がよく分からない。
  http://www.swissdelphicenter.ch/torry/showcode.php?id=2004

・お聞きしたい事項
  どのようにすれば、他のソフトに悪影響を出さず、Alt + Cを押したとき
  の音を消せるか。

・具体的なコード  (最上段のリンクからの引用です。)

var
  HookHandle: HHOOK;
  AltKeyDown: Boolean;

function KeyHook(Code: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
begin
  if (Code >= 0)and(Code = HC_ACTION) then begin
   if (LParam and $80000000) = 0 then begin
    case WParam of
     VK_MENU : AltKeyDown := True;
     ORD('C'): if AltKeyDown then ShowMessage('ALT+C');
    end;
   end else begin
    case WParam of
     VK_MENU : AltKeyDown := False;
    end;
   end;
  end;
  result := CallNextHookEx(HookHandle, Code, WParam, LParam);
end;


まこと  2010-07-05 06:43:50  No: 38749

書きもれてしまいました。追記させてください。
Windows XP Home + Delphi6 Personalを使用しています。


tor  2010-07-05 07:50:49  No: 38750

>Alt + C  が押されたとき、そのコンボボックスにフォーカスを移動させる
という目的だったら、
コンボボックスの前にアクセスキー'&C'を持つラベルを置いておけば
あとはダイアログマネージャが面倒を見てくれるのではないでしょうか。
(ちなみにエラー音が鳴るのは、そのアクセスキーを持つコントロールが
ダイアログ上にないためだと思われます)

実際試したわけではないので自信はないですが、
ラベルはTWinControlの派生クラス(例えばTStaticText)でないといけないかもしれません。
後は、タブオーダーがラベル→コンボボックスの順になるように気をつければいけるかと。


tor  2010-07-05 19:20:46  No: 38751

一応実験コード

type
  TCustomOpenDlg = class(TOpenDialog)
  private
    FComboBox: TComboBox;
    FLabel: TStaticText;
  protected
    procedure DoShow; override;
  public
    constructor Create(AOwner: TComponent); override;
    function Execute: Boolean; override;
  end;

constructor TCustomOpenDlg.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FLabel := TStaticText.Create(Self);
  FLabel.Caption := 'コード(&C):'; // アクセスキーを設定
  FComboBox := TComboBox.Create(Self);
end;

procedure TCustomOpenDlg.DoShow;
var
  rc: TRect;
begin
  // コントロールの親をダイアログにする
  FLabel.ParentWindow := Handle;
  FComboBox.ParentWindow := Handle;
  // 適当に配置
  rc := GetStaticRect;
  FLabel.Left := rc.Right; FLabel.Top := rc.Top;
  FComboBox.Left := rc.Right; FComboBox.Top := rc.Top + 16;
  inherited DoShow;
end;

function TCustomOpenDlg.Execute;
begin
  // TOpenPictureDialogの真似
  if NewStyleControls and not (ofOldStyleDialog in Options) then
    Template := 'DLGTEMPLATE' else
    Template := nil;
  Result := inherited Execute;
end;

これでAlt+Cでダイアログ内のコンボボックスにフォーカスが移動します。
ParentWindowを設定する必要があるので、やはりラベルはTStaticTextでないといけませんね。


まこと  2010-07-06 05:24:15  No: 38752

ご回答、ありがとうございます。
先ほど、TLabelをTStaticTextに置き換えて動かしてみました。
そうしたところ、無事、動きました。もう少しだけ動作を検証させていただき、
その後で解決とさせていただきたいと思います。

TStaticTextというヒントだけでなく、わざわざ検証までしていただいて、
本当に頭の下がる思いです。本当にありがとうございました。

※せっかくなので、これを適用した際に新しく発生した問題点を参考までに書いておきます。
  私の環境だけかもしれませんが、TCustomOpenDlg.Executeを2回以上実行すると、
  なぜかStaticTextのCaptionが空文字("")になってしまう現象が発生しました。
  (StaticTextの代わりにLabelを使っていたときは、こういう現象は全く起こらなかったのですが。)
  これに対応するため、TCustomOpenDlg.DoShow;のタイミングで、Captionに文字列を設定
  するという処理を追加で加えることとしました。


まこと  2010-07-20 05:58:57  No: 38753

ご報告が遅れて申し訳ありません。
  あの後、修正を適用後、しばらく使ってみながら同時に確認を行って
いたのですが、特に問題点等は発生しませんでした。ですので、これで
解決とさせていただきます。問題解決にあたり、ここでご回答をいただ
いたことは、非常に大きな助けとなりました。どうもありがとうござい
ました。


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








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