お世話になります。
MFCでWIN2000上で動くダイアログベースのアプリを開発中なのですが、
メインダイアログからボタンで3つのサブダイアログを表示するのですが、
ファイルが増えるのがイヤだったので3つとも同じクラスで作りました。
そのようにしたらメンバ変数を追加するとリソース以外のダイアログを
ボタンで開こうとするとエラーで落ちるようになってしまいました。
メンバ変数がないと問題ないのですが。
解決方法がわかりましたら教えていただけないでしょうか。
まだVC歴半年なので説明に間違いや分かりにくい所があると思いますが、
宜しくお願いします。
> リソース以外のダイアログ
ダイアログの情報(?)がリソース以外のところに定義されているという事でしょうか?
詳細がよくわからないのですが。
> メンバ変数がないと問題ないのですが。
メンバ変数を追加したのは、メインのダイアログですか?サブのダイアログですか?
読んでいてよく分からなかったので質問ですm(_ _)m
サブダイアログを1つ目作ってから、2つ目を同じクラスで
作ろうとするとリソースを変更しますか?みたいなことを
聞かれるのでそれでリソースを変更して3つのダイアログを
作ったのでリソースは最後に作ったサブダイアログになっています。
メンバ変数を追加したのはリソースになっているサブダイアログです。
そのサブダイアログはちゃんと開きます。
リソースエディタでダイアログのIDを以下の3つで作成していたとします。
IDD_DIALOG1
IDD_DIALOG2
IDD_DIALOG3
最初、IDD_DIALOG1でCDlgTestクラスを作成したとします。
次にIDD_DIALOG2を開いたままクラスウィザードを実行すると新規のクラスを作成するか、既存
のクラスにするか聞かれると思います。
で、既存のクラス(CDlgTest)にします。
するとCDlgTestクラスのIDがIDD_DIALOG1からIDD_DIALOG2に変わります。
同じようにしてIDD_DIALOG3で既存のクラス使用にします。
で、現在CDlgTestクラスのIDはIDD_DIALOG3になっているという事ですよね?
上記の方法で合っていると仮定した場合、IDがIDD_DIALOG3以外のダイアログはどうやって呼ぶ
のですか?
方法が分からないので教えて下さい。
メインのダイアログから
cog_Command *sys_command = new cog_Command(NULL);
sys_command->Create(ダイアログのID);
sys_command->ShowWindow(SW_SHOW);
を行っています。
3つのボタンがあってそれぞれのダイアログが表示されるように
なっています。
CDialogから派生したダイアログのコンストラクタでIDをCDialogクラスのコンストラクタに渡
していますよね。
それとCreateした時のIDが違うのって問題ないのでしょうか?
IDが違うとダメだと今まで思ってきたので、違うIDを設定した事がありません(関係ないのか
も?)
なので、どうやるのかな?と思っていました。
↑メンバ変数を作成する前は大丈夫だって事なので、平気なのか。
他はDoDataExchange内で使用しているIDが存在しないとか。
DoDataExchange内のIDはちゃんと合ってるみたいです。
メンバ変数を追加したリソースのダイアログはちゃんと表示されるんですよねぇ。
普通ダイアログごとにクラスを作ってファイルも作るんでしょうか?
それだとどんどんファイルが増えちゃうので管理が大変なんですよね。
> DoDataExchange内のIDはちゃんと合ってるみたいです。
> メンバ変数を追加したリソースのダイアログはちゃんと表示されるんですよねぇ。
テストで作成してみたんですが、IDの整合性が取れていればちゃんと表示出来ました。
て事はCDialogのコンストラクタに渡すIDとCrateに定義するIDは違っていても良いみたいです
ね。
> 普通ダイアログごとにクラスを作ってファイルも作るんでしょうか?
> それだとどんどんファイルが増えちゃうので管理が大変なんですよね。
少なくとも私は、今までそのやり方ですね。
コントロールが一緒で(数なども)別のダイアログとしたい場合はキャプションや(スタティッ
クコントロール含む)が違う位が殆どだと思うので、表示する前にそれらの文言を換えるのが簡
単だと思います。
コントロールの数が一緒で配置が違うとか言う場合は、ひろさんの方法が有効だと思います。
理由がわかりました。子ダイアログをクリエイトする時にDoDataExchange
でエラーになります。
メンバ変数を設定した子ダイアログ以外をクリエイトするとメンバ変数が
存在しないからエラーになってしまうんですね。
同じクラスなのに定義する毎にメンバ変数が有ったり無かったりする訳ありません。
メンバ変数じゃなくてIDがないって事なんじゃないですか?
そうですか、なるほど。
void Cxx::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_CBIndex(pDX, ID名, m_1);
//{{AFX_DATA_MAP(Cxx)
//}}AFX_DATA_MAP
}
となっていてID名はちゃんと存在するIDになってるんですけど、
この関数の中で
HWND CDataExchange::PrepareCtrl(int nIDC)
{
ASSERT(nIDC != 0);
ASSERT(nIDC != -1); // not allowed
HWND hWndCtrl;
m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
if (hWndCtrl == NULL)
{
TRACE1(Error: no data exchange control with ID 0x%04X.\n,
nIDC);
ASSERT(FALSE);
AfxThrowNotSupportedException();
}
のif文に入ってしまうんですよね。
ひろぴーさんの言うように、恐らく
IDで示す子コントロールがないからエラーが起きるってトコでしょうか。
1つのダイアログ上にある子コントロールを
クラスウィザードでメンバ変数として追加したけれど、
他のダイアログ上にはその子コントロールは無いからメンバ変数を処理出来ないという感じで。
(ここまで合ってるか自信ないです。)
>普通ダイアログごとにクラスを作ってファイルも作るんでしょうか?
>それだとどんどんファイルが増えちゃうので管理が大変なんですよね。
僕もMFCを使うときはダイアログごとにクラスを作ってますけど、
もしファイルが増えていってしまうことだけが嫌であれば、
1つのファイルに複数のクラス定義を書き込んではどうでしょ?
または、ダイアログを判別してメンバ変数の処理をするなど。
専らSDKでやっててMFCには詳しくないんで、
自分でも滅茶苦茶なコトを書いてしまった気もします。
間違ったことを書いてたらすみません。
だぁっ、かぶってしまったようです。すみません(^^;
おそらく風さんのいうとおりなんだと思います。
どのように解決すればよいのでしょうか?
素直にテンプレートごとにクラスを作ることをお勧めします。
解決能力が既に備わっているなら、できないことではないでしょう。
テンプレートごとの固有事情をひとつのクラスで吸収するには、
そのクラスのインスタンスがロードしたテンプレートを認識し、
それぞれの事情ごとに各所で処理振り分けするようにすればよい。
しかし、サポートするテンプレートが増えるほどに処理は複雑化し、
ファイルの数が増える負担より、処理の複雑化をメンテナンスする負担のほうが大きくなる。
また、メンバ変数が増えたクラスインスタンスは無用にメモリを圧迫することになるだろう。
従って、可能であってもよほどの理由が無ければ、誰もそのようなことはしないと思う。
自力解決の能力が無く、問題が起きるたびに人に聞かなければできないようなら、
なおさらやるべきではないと思ふ。
いじょ。