アトリエ ぺっぺ

トップページ > プログラムTips > ダイアログとリソースID

◆ ダイアログとリソースID
IDの変更に伴う注意点
 
● 変更によるResource.h再読み込み
リソースIDはプロパティを操作することにより変更することが出来ます。
好みにもよりますが、そのボタンの機能と揃えたほうが分かりやすいでしょう。
 

 
こうした場合、Resource.hも自動で書き換わってくれます。
 

 
ちなみに、このようにResource.hが自動に書き換わるときResource.hを開いていると、
下記のようなダイアログが表示されます。
 

 
このときは必ず「はい」もしくは「すべてに適用」を押下してください。
変更の反映されたResource.hが再読み込みされ、表示されます。
このときもし「いいえ」を選んで、うっかり反映前のデータで上書き保存してしまうと、
Resource.hと実際のコントロールのID(***.rcに保存されています)がずれてしまう可能性があります。
自動で再読み込みしろコンチクショウ。と思うのは俺だけ?
 
● メンバ変数への「無」反映
コントロールにはメンバ変数を作ることが出来、それをあたかもコントロール本体のように使用することが出来ます。
※ IDC_STATICをIDに持つコントロールにメンバ変数を作ることは出来ません。
それらのコントロールにメンバ変数を作りたい場合は、リソースIDを別なものに振りなおしてください。
コントロールのメンバ変数を作るには、次のようにします。
@ ダイアログエディタ上でメンバ変数を作りたいコントロールを右クリックし、[変数の追加]を選択。
 

 
A 「メンバ変数の追加」ダイアログで、変数名に好きな変数名を入力、完了ボタンを押下。
 

 
B ダイアログクラスに、メンバ変数として宣言されます。
 

 
これだけではどのようにコントロールとメンバ変数が関連付けられているか分かりません。
実はダイアログクラスのDoDataExchange()という関数に、その関連付けが書かれています。
 

 
ここではDDX関数の詳しい説明は省きますが、この関数で、リソースIDと変数自体を結び付けているらしいことは分かるでしょうか。
 
◎ さて、DoDataExchange関数でリソースIDと変数を関連付けしていることはホンワカ分かっていただけたと思いますが、
では変数を作った後、ダイアログエディタでリソースIDを変更したらどうなるでしょうか。
Resource.hのように、DoDataExchange関数も変わってくれるのでしょうか?
 
残念ながら、答えはNoです。
 
Resource.hと違い、プログラマが任意で加えた変更(メンバ変数の作成)に対しては、そこで使っているリソースIDが変更されたとしても、VCは自動では変更を反映してくれません。
また、リソースIDの変更があったとき、そのリソースIDがどこでも使用されていないIDであれば、そのリソースIDはResource.hから自動で削除されますが、CPPに書かれているリソースIDは「使用されているID」と認識され、Resource.hから削除もされません。
どういうことかというと、メンバ変数の作成→対応するコントロールのリソースID変更→コンパイル・ビルドという順番で処理を行ったとき、DoDataExchange関数には古いままのリソースIDが残ったまま、ビルドが正常終了してしまいます。
 
このようにして作られたダイアログはもちろん正しい動きはしません。
DoDataExchange関数はダイアログが作成・表示されるときに呼ばれます。
このとき、リソース上にないリソースIDと変数を結び付けようとして失敗し、容赦なく落ちてくれます。
 

↑デバッグモードで表示しようとしたときに出るダイアログ
 
回避策としては、
@ メンバ変数を作った後は、リソースIDは変更しない
A 手書きでDoDataExchange関数を変更する
がありますが、なるべくメンバ変数を作った後は、リソースIDは変更しないようにしましょう。
 
また、ダイアログが表示されるタイミングで上記のようなエラーになるときは、このDoDataExchange関数がクサいことが多いです(同じくらいクサいのはOnInitDialog関数)。
もしそのようなことになったら、ブレークポイントを置いて、確かめてみてください。
 
● イベントハンドラへの「無」反映
何をいわんや、前の項とほぼ同様の内容です。
ボタンクリック等、コントロールのイベントに対応する関数は、例えばボタンならボタンをダブルクリックするか、ウィザードによって作成することが出来ます。
イベントに対応する関数のことをイベントハンドラと言いますが、そのイベントハンドラをウィザードによって作成する方法は次のとおりです。
@ イベントハンドラを加えたいコントロールを、ダイアログエディタ上で右クリック、[イベント ハンドラの追加]を選択します。  

 
A 「イベントハンドラ ウィザード」ダイアログボックスでメッセージの種類を選択します。
  ハンドラの種類は、下部の「ハンドラの種類」の項に表示されますので、それを見つつ選ぶといいでしょう。
  また、関数ハンドラ名はデフォルトの名前が表示されますが、ここを自分の好きな名前に変更することも可能です。
 

 
B 追加して編集ボタンを押下すると、ダイアログクラスにイベントハンドラ関数が追加されます。
 

 
この関数もメンバ変数のときと同様、どのコントロールと結びついているかが、同CPPの上のほう、MESSAGE_MAP内に宣言されています。
 

 
これが何を表しているかというと、
ON_BN_CLICKED「ボタンが押された」と言うイベント
IDC_BTN_SAVE「押されたボタンのリソースID」
OnBnClickedBtnMoranbon「対応するイベントハンドラ」
という具合です。
この部分も、メンバ変数のときと同様、ダイアログエディタでのリソースID変更は反映されません。
ただメンバ変数と違い、ダイアログを表示させても、落ちたりしません。
 
なぜかと言うと、このメッセージマップというものは、「ボタンが押されたよ」というメッセージが来て、「どれどれ、ボタン押下メッセージに対応する関数はあるかな?」という感じに、メッセージが来て初めて参照されるフィールドだからです。
そして、ボタンが押されたというメッセージと、押されたボタンのリソースボタンの組み合わせを探し、もしなかったらダイアログは何も行いません。
 
つまり、イベントハンドラを作成した後、うっかりリソースIDを変更してしまった場合、せっかく作ったイベントハンドラは一生呼ばれない関数となってしまいます。
 
落ちたりしない分、気付きにくいという点で、メンバ変数の場合よりもたちの悪いバグになる可能性があるので、気をつけましょう。
 
また万が一リソースIDを変更してしまった場合、このメッセージマップ部分を手で修正することになるのですが、
そのときに元のリソースIDが「IDC_BUTTON1」「IDC_BUTTON2」だったりすると、もう何のボタンだったかさっぱり分からなくなったりします。
そのようなことがないためにも、コントロールを配置した際には、できるだけ早々に分かりやすいリソースIDに書き換えるように習慣をつけてしまいましょう。
項目のTOPへ
 

(C) 2002 atelier-peppe
ababa@atelier-peppe.sakura.ne.jp