ダイアログボックスについての質問です。
開発環境は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
No.2ベストアンサー
- 回答日時:
★アドバイス
・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→『ボタンのフォーカスについて』
↑リンク先を参考に。
・以上。おわり。
返答ありがとうございました。
サブクラス化したプロシージャから親のダイアログボックスで定義されているCombo Boxの情報を取得する関数の存在を知りませんでした。
とてもためになる知識を教えていただきありがとうございます。
>とはなぜ WM_CREATE メッセージのタイミングで描画を行わせたいのですか?不思議です。
Oh-Orangeさんが予想されるように、ダイアログボックスが表示される瞬間から描画を開始したいと思っていたので、WM_CREATEメッセージで描画を行うように記述しました。
わかりにくくて申し訳ないです。
しかもそのパターンにあわせてサンプルまで記述していただきありがとうございました!
*フォーカスについて:
アドバイスに従いcase WM_SETFOCUS: return 0;と記述した結果うまくフォーカスを消すことができました。
ありがとうございました。フォーカス処理を空にしてしまうのですね。
納得です^^
ありがとうございました。
No.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ですよね?
返信ありがとうございました。
確かにWM_PAINTはいつ呼ばれるか分かりませんよね・・・
ダイアログボックスを移動しただけでも呼ばれるし・・・
そして呼ばれるたびに同じ画像を表示しなければならないからnumberをプロシージャ内で保持していなければいけないです。
こう考えるとグローバル変数を利用するしかないようですね。
参考意見ありがとうございました。
もうちょっと考えてみようと思います。
>Picture ControlのプロシージャでWM_CREATEメッセージを受け取り描画を行う。
>WM_PAINTですよね?
ダイアログボックスが表示された時点でPicture Controlに画像を表示させたいのです。
そのためWM_CREATEの時点で表示をおこなっています。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) エクセルマクロでアニメを作る方法を教えてください。 1 2023/02/07 14:27
- Visual Basic(VBA) ExcelのVBAコードについて教えてください。 1 2023/04/21 13:46
- HTML・CSS 自身のHPにYouTube動画を貼り付けるのが出来なくなり困ってます 1 2022/11/11 10:44
- MySQL `picture` varchar(255) のコマンドで間違いないでしょうか? 1 2022/11/21 04:08
- MySQL PHP 画像のアップロード Qiita 2 2022/11/28 04:44
- Google Drive Googleドライブの警告メッセージを消す方法 4 2022/09/21 06:04
- JavaScript ①入力フォーム→②確認表示画面→③送信完了画面のコードを書いているのです、 入力フォームから受け取っ 2 2022/05/10 16:45
- WordPress(ワードプレス) WordpressでYouTubeの埋め込みができない。 1 2022/10/26 01:08
- 格安スマホ・SIMフリースマホ UQモバイルで、LINEが機能しないのはなぜ? 2 2022/08/19 11:19
- HTML・CSS WEBサイトの構築。表示データとWEBデザインを分離する考え方を専門用語・業界用語では何と言うか? 8 2022/09/27 09:16
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
MFCでOnPaintのタイミング
-
Windowのちらつき防止
-
word
-
InvalidateRectの使い方について
-
ダイアログベースの再描画について
-
TextBoxに文字を書いても表示さ...
-
FPS リフレッシュレートとフレ...
-
GDI+について
-
VB.NETでPictureBoxへの描画に...
-
[VB.net] DataGridViewの列ヘッ...
-
OneNote 2010 文字と描画がずれる
-
C# ラバーバンドの描画を快適に...
-
VB.netでのライン描画方法がわ...
-
Visual Studio.Netで株価チャー...
-
NVIDIAのシェーダーキャッシュ
-
フラッシュで正六角形を作る方法
-
クライアント領域の保存
-
逐次的なグラフ表示の方法
-
矢印を描画するには
-
gnuplotのフリーズについて
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
PCで「使用可能な場合はグラフ...
-
[VB.net] DataGridViewの列ヘッ...
-
UpdateData( FALSE); による文...
-
NVIDIAのシェーダーキャッシュ
-
VB6,リストボックスの特定行の...
-
TextBoxに文字を書いても表示さ...
-
word
-
MFCでOnPaintのタイミング
-
エクセルでガンチャートを作成...
-
MFCのタイマーのつかい方を教え...
-
InvalidateRectの使い方について
-
VC++プログラムをつかったBMP画...
-
CScrollViewの使用方法について
-
VB.netでのライン描画方法がわ...
-
CStaticコントロールの静的イメ...
-
Labelの文字をスクロールする際...
-
Form1 Load で実行されない。
-
VBAにGDI+を参照させる方法
-
C++にて、塗りつぶされた円を描...
-
GetGlyphOutline() ご利用経験...
おすすめ情報