こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

ダイアログボックスについて。

ダイアログボックスについての質問です。
開発環境はVisual C++ 2005.netでありSDKを利用しています。

ダイアログボックスにPicture Controlを貼り付け、Combo Boxの内容が変わるたびにそのPicture Controlに画像を表示するようなプログラムを作りたいと考えています。

自分が考える手順としてはまずPicture Controlについてサブクラス化を行い、親のダイアログボックスが表示されると同時にPicture ControlのプロシージャでWM_CREATEメッセージを受け取り描画を行う。

そして親のダイアログボックスに貼り付けたCombo Boxの内容が変更された場合に、Picture ControlのウィンドウハンドルにむけてWM_PAINTメッセージを送信する。

こんな手順で行いたいのですが、少し不安な部分が出てきました。
Combo Boxの内容が変更され、Picture Controlのウィンドウハンドルに向けてWM_PAINTメッセージを送信し、Picture ControlプロシージャではWM_PAINTメッセージがきたとき画像の描画を行う場合、このプロシージャではどの画像を描画してよいか不明です。 そのため何番の画像の表示命令が来たのかを示すために、親のダイアログボックスに貼り付けたCombo Boxが変更された場合、Picture Controlに向けてWM_PAINTメッセージと表示画像番号をパラメータとして送信したいのです。

もちろんグローバル変数を用意すれば簡単なのですが、できるだけ使用しないように記述をしたいのです。そこで考えたのが、

SendMessage(GetDlgItem(hDlgWnd, IDC_PICTURE), WM_PAINT, 0, MAKELPARAM(0, number));

このようにnumberをLPARAMの下位ワードとして送信しようと考えました。

このメッセージ送信を行い、Picture ControlプロシージャでWM_PAINTメッセージが到着したとき、LOWORD(lparam)からnumberを取り出す。



実現したい目的のため、このような方法を考えましたが、エラーなく実行できるでしょうか?

もしあやしい部分が見つかった場合はアドバイスをお願いします。そしてこの方法よりも簡単に処理できる方法があれば教えていただきたいです。
自分としてはサブクラス化は面倒なので、Picture Controlをオーナードローとして扱う方法も考えましたが、うまく動きませんでしたTT

投稿日時 - 2007-05-15 10:38:03

QNo.3001576

すぐに回答ほしいです

質問者が選んだベストアンサー

★アドバイス
・Picture Control で親のコンボボックスの選択されている位置(内容)を取得すれば
 SendMessage() 関数を利用しなくても良いと思います。
 下にそのサンプルを載せます。

サンプル:
case WM_PAINT:
{
 TCHAR szBuff[ MAX_PATH ]; ←文字列の取得用
 HWND hParent; ←親のウインドウハンドル
 INT nPos; ←これがコンボボックスで選択されている位置(0~)
 
 hParent = GetParent( hWnd ); ←hWnd は Picture Control のウインドウハンドル
 nPos = (INT)SendDlgItemMessage( hParent, IDC_COMBOBOX, CB_GETCURSEL, 0, 0 );
 ↑選択位置が描画画像番号になるならば nPos をそのまま使う。
 
 SendDlgItemMessage( hParent, IDC_COMBOBOX, CB_GETLBTEXT, (WPARAM)nPos, (LPARAM)szBuff );
 ↑選択位置からコンボボックスに設定されている文字列を szBuff に取得する。
  :
 その他の処理
  :
 break;
}

解説:
・上記のは Picture Control の WM_PAINT 部分です。
 GetParent() 関数で親のウインドウハンドルを取得して、そのハンドルからコンボボックスの
 位置、文字列内容などを取得することが出来ます。もし、親ウインドウにコンボボックスが1つ
 しかない場合は上記の方法が利用できます。複数ある場合はちょっとだけ工夫が必要になります。
・あと気になったことで
>WM_CREATEメッセージを受け取り描画を行う。
 とはなぜ WM_CREATE メッセージのタイミングで描画を行わせたいのですか?不思議です。
 ダイアログの起動時にも指定画像を描画させたくて『描画番号』を送りたい場合には、DialogBox()
 ではなくて DialogBoxParam() マクロ関数を利用します。つまり、
 int number = (描画番号);
 
 DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG), hWnd, DialogProc, (LPARAM)&number );
 とダイアログを表示させます。
 そして、ダイアログの WM_CREATE メッセージ内で
 case WM_CREATE:
 {
  int number = *(int *)lParam; ←これで親ダイアログからの描画番号のポインタを受け取れる。
   :
  その他の処理
   :
  break;
 }
・上記の方法を使えば、グローバル変数を利用しなくても親の持つ変数(構造体)などもそっくりと
 子のダイアログに受け渡せます。

その他:
・フォーカスの点線の消し方の簡単な方法を見つけましたので紹介します。
 スライダー(トラックバー)のコントロールをサブクラス化した時、WM_SETFOCUS メッセージを
 次のように書き換えます。
 case WM_SETFOCUS: return 0;
 この1行でフォーカスの点線を消せます。
 前々回のアドバイスでは、PostMessage を使う方法でしたが必要ありません。
 親ダイアログの WM_COMMAND の IDC_SLIDER1 ~ IDC_SLIDER3 などの記述も必要ありません。
 WM_SETFOCUS メッセージを処理(中身空っぽに)すればフォーカスの点線を表示されません。
http://forums.belution.com/ja/vc/000/001/51s.shtml→『ボタンのフォーカスについて』
 ↑リンク先を参考に。
・以上。おわり。

投稿日時 - 2007-05-15 14:58:16

お礼

返答ありがとうございました。

サブクラス化したプロシージャから親のダイアログボックスで定義されているCombo Boxの情報を取得する関数の存在を知りませんでした。

とてもためになる知識を教えていただきありがとうございます。



>とはなぜ WM_CREATE メッセージのタイミングで描画を行わせたいのですか?不思議です。

Oh-Orangeさんが予想されるように、ダイアログボックスが表示される瞬間から描画を開始したいと思っていたので、WM_CREATEメッセージで描画を行うように記述しました。
わかりにくくて申し訳ないです。
しかもそのパターンにあわせてサンプルまで記述していただきありがとうございました!



*フォーカスについて:
アドバイスに従いcase WM_SETFOCUS: return 0;と記述した結果うまくフォーカスを消すことができました。
ありがとうございました。フォーカス処理を空にしてしまうのですね。
納得です^^

ありがとうございました。

投稿日時 - 2007-05-15 15:49:23

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.1

>SendMessage(GetDlgItem(hDlgWnd, IDC_PICTURE), WM_PAINT, 0, MAKELPARAM(0, number));
WM_PAINTは自分が呼ぶだけではありません。
WM_PAINTは意図しないタイミングでOS側から呼ばれる事もあります。
というか描画の度に呼ばれているウインドウメッセージです。
WM_PAINTはLPARAMもWPARAMも使わないようなのでウインドウメッセージなので実行には問題はないでしょうが
どちらにしてもIDC_PICTUREのWM_PAINT内でそのnumberを保持する必要があるでしょう。
結局、関数内部でstatic変数で持つかグローバル変数なりで持つしかないということです。
もちろんグローバル変数を直に持つのはコード的に綺麗とはいえないため
どういうコードが美しいかは人によりますが一つの例として
WndProcをラップしたクラスを作り、メンバ変数として持つ等の方法はあります。

やはりint g_number;等のグローバルで持つのが単純ですが、その場合は
コンボボックス変更時に
g_numberを変更し、
InvalidateRect( GetDlgItem(hDlgWnd, IDC_PICTURE) , bull , FALSE )等で再描画を促します。

>Picture ControlのプロシージャでWM_CREATEメッセージを受け取り描画を行う。
WM_PAINTですよね?

投稿日時 - 2007-05-15 14:40:59

お礼

返信ありがとうございました。

確かにWM_PAINTはいつ呼ばれるか分かりませんよね・・・
ダイアログボックスを移動しただけでも呼ばれるし・・・

そして呼ばれるたびに同じ画像を表示しなければならないからnumberをプロシージャ内で保持していなければいけないです。

こう考えるとグローバル変数を利用するしかないようですね。
参考意見ありがとうございました。
もうちょっと考えてみようと思います。



>Picture ControlのプロシージャでWM_CREATEメッセージを受け取り描画を行う。
>WM_PAINTですよね?

ダイアログボックスが表示された時点でPicture Controlに画像を表示させたいのです。
そのためWM_CREATEの時点で表示をおこなっています。

投稿日時 - 2007-05-15 15:39:14

あなたにオススメの質問