BN_CLICKされずにフォーカスを持ったままになっている状態を知るには

[戻る]
JILL 2010/10/21(木) 18:09:31
WindowsCE5.0/eMbeddedVC++4.0SP4/SDK(MFC未使用)にて開発

 お世話になります。
タイトルにうまく表現できなかったのですが、
コマンドボタンとエディットを含むダイアログボックスで
常にエディットにフォーカスを持っていたいので
コマンドボタンがクリックされた後に
エディットにフォーカスをセットしています。
クリックされた場合はいいのですが、
ボタンをへこませた状態のまま、ボタンの外にマウス
(WindowsCEではマウスではないのですが)を
ボタンの脇に移動した場合は、当然クリック動作はしません。
この場合、ボタンにフォーカスが移ったままになってしまうのですが
この状態に移ったことを捕まえるにはどうしたらよいのでしょうか?

仲澤@失業者 2010/10/22(金) 16:30:36
確実な方法は見つかりませんが、この場合はボタンにフォーカスが
移動してしまうのを防ぐのが近道かもしれません。
DLG内の唯一のコントロールにフォーカスを与え続けるには、

1.DLG内の他のコントロールがフォーカスを取得したとき、
  親のDLGにフォーカスを移動させるようにする。
2.DLGは、自分にフォーカスが来たときは、その唯一のコントロールに
  フォーカスを当てるようにする。

このような動作をさせる場合は、そのコントロール(ボタンなど)を
サブクラス化する必要があるでしょう。

ryo 2010/10/22(金) 17:34:57
常にフォーカスを固定したいということは
「TABキーなどで、ボタンにフォーカスをあてて、ENTERを押す」といった使い方はしない
ということであってますでしょうか?

ボタンを押す方法が、ポインタデバイスによるクリック(タッチパネルなどもこみ)のみ
とするなら
「ボタンコントロール」をやめてしまい、
ダイアログ上に対し、LBUTTONUP・DOWNをうけとるようにし、
その位置がボタンの領域と定めた場所だったら、その対応した処理をする・・・
とすればかなり楽です

#動作によってはSetcaptureとか駆使したり、
#見せ掛けのボタンの絵を描画をする必要ありますが

JILL 2010/10/26(火) 11:47:20
仲澤@失業者さま、ryoさま ありがとうございます。

説明が不足しておりご迷惑をおかけしました。
ボタンコントロールは、クリックしたらエディットの入力値を検査し
OKである場合にダイアログを終了させる役目があります。
なので、ボタンコントロールのクリック動作は必要です。

仲澤@失業者さま
>1.DLG内の他のコントロールがフォーカスを取得したとき、
>  親のDLGにフォーカスを移動させるようにする。
私なりに試したのは、ボタンがフォーカスを取得した場合に
エディットコントロールにフォーカスをセットするというやり方です。
この場合はクリックが無効になってしまい。永遠にダイアログが終了しません。
親のDLG経由にした場合は大丈夫なのでしょうか?
試してみます。(ちょっと時間がかかりそうです)

ryoさま
>ボタンを押す方法が、ポインタデバイスによるクリック(タッチパネルなどもこみ)の>とするなら
そのとおりです、TABキーは存在しないので気にする必要はありません。
が、「ボタンコントロール」をやめてしまう→「コントロールなしでボタンの
ような動きをする制御を行う。」ということですよね。
ボタンの動きは仕様上必要で、疑似ボタンコントロール制御を確立するのは
スキル上、日程上私には無理そうです。

ロマ 2010/10/26(火) 13:30:43
HeaderControlかToolbarを流用するのはいかがですか。

HeaderControlはWindowsXPのクラシックスタイルだとボタンに似た外観です。
XPスタイルだとWM_INITDIALOGでWS_BORDERを追加しSetWindowPos(SWP_FRAMECHANGED)で
外枠を描くことができます。(.rcではうまくいかなかったです)
# 残念ながらマウスをボタンの上に置いたときのオレンジの枠は下線になります。

Toolbarは試していませんが、CCS_NORESIZEで任意の場所に配置できますし、
タスクバーのようなボタンを作ることもできると思います。

仲澤@失業者 2010/10/26(火) 17:45:06
>私なりに試したのは、ボタンがフォーカスを取得した場合に
>エディットコントロールにフォーカスをセットするというやり方です。
>この場合はクリックが無効になってしまい。永遠にダイアログが終了しません。

フォーカスを取得した瞬間でもOKだと思っていたのですが、だめなら、
WM_LBUTTONUPタイミングでフォーカスをエディットなり
親なりに設定してみてはどうでしょう。

PATIO 2010/10/26(火) 19:00:45
フォーカス関連の描画をいっさい行う必要が無いのであれば、
押される前の画像と押された時の画像を二枚用意しておいて
クリックされたタイミングで入れ替えるだけなのでそこまで
大変ではないような気もします。

フォーカス関連の描画までやるとなると状態管理が必要になるので
かなり面倒になりますけれど。
確かに押されたと言う確認がほしいだけであれば、
そこまで敷居が高くないのではないでしょうか。
後は何処まで既存のコントロールに似せるかと言う話だと思います。

ロマ 2010/10/26(火) 20:39:07
ボタンのサブクラス化なら、

#include <windowsx.h>
WNDPROC orgButtonFunc;
LRESULT CALLBACK ButtonFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM 
lParam)
{
  static HWND hwndReFocus; //ボタンが複数ならSetProp/GetPropに変えてください
  switch(message)
  {
  case WM_LBUTTONDBLCLK:
  case WM_LBUTTONDOWN:
    hwndReFocus = GetFocus();
    break;
  case WM_CAPTURECHANGED:
    PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, (WPARAM)hwndReFocus, TRUE);
    break;
  }
  return CallWindowProc(orgButtonFunc, hwnd, message, wParam, lParam);
}

//ダイアログ関数で
case WM_INITDIALOG:
  HWND hwndButton = GetDlgItem(hDlg, IDC_BUTTON1);
  orgButtonFunc = SubclassWindow(hwndButton, &ButtonFunc);

こんな感じです。ただし、充分なテストが必要です。

JILL 2010/11/06(土) 16:01:31
[[解決]]
みなさま、ありがとうございます。
貴重なご意見を元に、スーパークラス化してみました。(数が多いので)
ダイアログによって、処理を変えたいので、ボタンにフォーカスが残らないように
親ウィンドウにフォーカスをセット(その後はダイアログにより処理を変えられる
ように)しました。なんとか、希望に沿っていそうなので解決とします。

一応、ご参考まで。

static    TCHAR        s_pbNewClassName[] = TEXT("MYBUTTON");    // 独
自コントロール用のクラス名
static    WNDPROC        s_lpfnDefButtonProc;            // 
Windowsがあらかじめ用意している BUTTON ウィンドウクラス用処理を保存
LRESULT CALLBACK ButtonProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    static    WNDPROC lpfnDefButtonProc = NULL;
    HWND    parent_hwnd;

    parent_hwnd = GetParent( hwnd );    // 親ウィンドウの取得
    switch (msg){
    case WM_CREATE:        // 
        lpfnDefButtonProc = (WNDPROC)((LPCREATESTRUCT)lParam)-
>lpCreateParams;    //デフォルトのプロシージャを保存
        break;
    case WM_COMMAND:
        switch( HIWORD(wParam) ){
        case BN_CLICKED:
            break;            // 従来の処理
        default:
            return 0;        // 通知しない
            break;
        }
        break;
    case WM_CHAR:
        PostMessage(parent_hwnd, WM_CHAR, (WPARAM)wParam, 0);    // 親
ウィンドウでキーが押されているメッセージとする
    case WM_CAPTURECHANGED:
        SetFocus( parent_hwnd );        // 親ウィンドウにフォーカ
スをセットする
        return 0;
        break;
        }
    // デフォルトのプロシージャを保存を呼び出す
    return CallWindowProc(lpfnDefButtonProc, hwnd, msg, wParam, lParam);
}
HWND s_CreateButton(HWND m_hwnd, UINT id, DWORD myStyle,HWND e_hwnd,RECT b_rs)
{
    e_hwnd = GetDlgItem(m_hwnd, id);
    if (e_hwnd !=NULL){                    
    // 既存のコントロール
        s_GetClientRect(m_hwnd, e_hwnd, &b_rs);        
    // クライアント座標取得
        DestroyWindow( e_hwnd );            // 既存のコント
ロールを破棄
    }
    // 指定位置とサイズで生成
    e_hwnd = CreateWindow(s_pbNewClassName, s_pbNewClassName, myStyle,
        
        b_rs.left, b_rs.top, b_rs.right-b_rs.left, b_rs.bottom-
b_rs.top,
        m_hwnd, (HMENU)id,g_hInst, s_lpfnDefButtonProc);
    return e_hwnd;
}
BOOL    cnt_InitialMyPushButtonClass(HINSTANCE m_hInstance)
{
        BOOL        ret;
        WNDCLASS    wc;

        //独自エディットクラスの登録
        ret = GetClassInfo(g_hInst, TEXT("BUTTON"), &wc);
    //Windowsがあらかじめ用意しているウィンドウクラスデータ取得
        s_lpfnDefButtonProc = wc.lpfnWndProc;        // 
Windowsがあらかじめ用意しているウィンドウクラス用処理を保存
        wc.hInstance        = m_hInstance;        
    //このウィンドウクラスを登録するアプリケーションのインスタンスハンドル
        wc.lpfnWndProc   = ButtonProc;            
    // 独自コントロール用の処理に置き換え
        wc.lpszClassName = s_pbNewClassName;        // 独自コントロ
ール用のクラス名登録
        if (RegisterClass(&wc) == 0){
            return FALSE;
        }
        return TRUE;
}

古いスレッドには追加発言できません。