いつもお世話になっています。
ダイアログベースでプログラムを作成しています。
そこで、最初に作られるダイアログ上のボタンをクリックすると、別のダイアログがあらわれ、
さらにその上のボタンをクリックするとカラーダイアログが呼ばれるようにしたいと思っていま
す。このために、2、3番目のダイアログのクラスで1番目のダイアログのクラスで定義したメ
ンバ変数を使用したいのですが、うまくいきません。
プログラム名を仮にBookとしますと、最初のダイアログのクラスは
class CBookDlg : public CDialog
となります(自動作成)。そこで、クラスウィザードなどで、2番目のダイアログのクラスを
class CBookSecondDlg : public CDialog
のように作ってしまうと、CBookDlgのメンバ変数を参照できませんでした(当然ですが)。か
といって、自分で
class CBookSecondDlg : public CBookDlg
のように作ってしまうと、CBookSecondDlgのダイアログ上のボタンをクリックした時の関数
(On Button等)をどう作ればいいのか分からなくなりました。
CDialogとCBookDlgの多重継承もやってみましたが、エラーが出てしまいます(同一名の関数等
があるからだと思いますが)。いっそ、グローバル変数でも定義したいと思ったのですが、どこ
で定義していいのか.....(BookDlg.hなどに書いてみたのですがダメなんですね.....)
やっているうちに、どんどん混乱してきてしまったのですが、対処法を教えて頂けないでしょう
か。お願いいたします。
非常にわかりにくい文章だと思いますがお許し下さい。
MFC VC++6.0 WIN2000
正しいやり方かどうかわかりませんが以下のようにしたらできました。
//dlg.h
class CBookDlg:public CDialog{
public:
char *http;//コンストラクタで初期化する
りゃく;
];
//dlg2nd.h
#includedlg.h
class CBook2nd:public CDialog{
public:
void OnOpen(){
::ShellExecute(NULL,open,top.http,NULL,NULL,SW_SHOWNORMAL);
}
りゃく;
};
すいませんぬけてました
//dlg2nd.h
#includedlg.h
class CBook2nd:public CDialog{
public:
CBookdlg top;//ここ抜けてる
void OnOpen(){
::ShellExecute(NULL,open,top.http,NULL,NULL,SW_SHOWNORMAL);
}
りゃく;
};
2,3番目のクラスで、最初のダイアログのメンバを取得の仕方ですが、
最初のダイアログがメインウィンドウになってると思うので、
CBookDlg* pDlg = (CBookDlg*) ::AfxGetMainWnd();
pDlg->取得したいメンバ;
というのでは、どうでしょうか。
または、最初のダイアログが親ウィンドウになるのなら、
CBookDlg* pDlg = (CBookDlg*) GetParent();
pDlg->取得したいメンバ;
でも出来ますね。
(たぶん、3番目のダイアログの親は2番目になると思うので、
3番目ではGetParent()を2回呼ぶはめになりますが・・・。)
あとは、2番目のダイアログのCBookSecondDlgクラスに
最初のダイアログへのポインタをメンバとして持たせるってのもありかもしれません。
継承などのあたりは少し勘違いがあるように感じます。。。
すいません、GetParent() を使う場合ですが、
GetParentOwner() を使えば3番目でも問題ないですね。
(3番目の親が2番目、2番目の親が最初のダイアログの場合。)
わたしならポインターを渡す方法かデーターをやり取りする方法かを使います
やり取りしたいデータ群を例えば class CBookData とか struct CBookData とか
に纏(まと)めておいて、これを各 CBookDlg, CBookSecondDlg のメンバーにして
相互にやり取りできるようにすればいいのでは?
私自身はこれらのメンバーは public にはせずに、受け渡し用のメンバー函数を作ります
const CBookData& CBookDlg::Data() const:
bool CBookSecondDlg::Data(const CBookData& data);
といった感じですね
そもそもアプリケーション全体で参照したいデータが、
最初のダイアログに所属しているために、
ややこしくなっているのではないでしょうか?
あちこちから参照したい変数ならば、
グローバル変数にするかCBookAppのメンバーにするのが妥当だと思います。
CBookAppのインスタンスは、もともとグローバル変数として
定義されていますので、book.hファイルでexternしておけば、
どこからでも、theAppにアクセスできます。
// book.h
class CBookApp
{
//...
public:
Data data;
};
extern CBookApp theApp;
>extern CBookApp theApp
これは考え付きませんでした。
これなら
/////////////////
class CBookdlg2nd{
public:
CBookdlg top;//(☆)実体化気に食わない
/////////////////
(☆)の部分も解決です。
walQさん、西風さん、島さん、dairygoodsさんありがとうございます。
みなさんのアドバイスから、現在の私の知識で手が付けられそうなのは、西風さんと
dairygoodsさんのやりかただと思い試しています(walQさん、島さんごめんなさい....)
dairygoodsさん
extern CBookApp theApp をすることで、アクセスできるようになりました。ありがとうござ
います。もし、(本当の?)グローバル変数にしたい場合には、どこのヘッダーファイルで定義
すればよろしいのでしょうか。
西風さん
CBookSecondDlgクラスに最初のダイアログへのポインタをメンバとして持たせる方法を試しま
した。
//BookSecondDlg.h
#include BookDlg.h
class CBookSecondDlg : public CDialog
{
・・・・・
public:
CBookDlg *pBookDlg;
};
しかしこれで、
//SetColorDlg.cpp
void CSetColorDlg::OnSetDialogColor()
{
CColorDialog dialogColorDlg(pTimerDlg->dialog_color);
if(dialogColorDlg.DoModal() == IDOK){
pTimerDlg->dialog_color = dialogColorDlg.GetColor();
}
}
のように記述すると、コンパイルは通るのですが、OnSetDialogColor()がよばれたときに、
「メモリがwrittenになることはできませんでした」のようにエラーが出ます。これはなぜでし
ょうか。
また、親ウィンドウや子ウィンドウというものが理解してませんで、どのようにすれば子(親)
ウィンドウとして成り立つのでしょうか。親、子と継承とは全く別問題ですか?
今のところGetParentOwner()やAfxGetMainWnd()を使うやりかたは、うまくいった(と思いま
す。まだ、色をかえるところまでは作っていませんが)
人に聞いてばかりで大変申し訳ないのですが、ご教授お願いします。
void CSetColorDlg::OnSetDialogColor()
{
CColorDialog dialogColorDlg(pBookDlg->dialog_color);
if(dialogColorDlg.DoModal() == IDOK){
pBookDlg->dialog_color = dialogColorDlg.GetColor();
}
}
の間違いです。それとdialog_colorはCOLORREF型のCBookDlgのメンバ変数です。
CSetColorDlg(CBookSecondDlg??) を作成したときに、
pBookDlg に CBookDlg へのポインタを渡してあげたでしょうか?
そのようなエラーは解りませんが、これくらいしか原因が思いつかないので。。
親ウィンドウと子ウィンドウの関係と、クラスの継承との関係は全く違いますねー。
その辺は、検索などで調べた方が解りやすいし、勉強になると思います。
個人的な話になりますが、
僕も沢山のクラス内で参照する値ならば dairygoodsさんと同じように、
アプリケーションクラス (CBookApp) で宣言しちゃいますね。
(クラスの取得は ::AfxGetApp() を使っていますが・・・。)
西風さん、ありがとうございます。
>CSetColorDlg(CBookSecondDlg??) を作成したときに、
>pBookDlg に CBookDlg へのポインタを渡してあげたでしょうか?
たぶん渡してないと思うのですが、具体的にはどうすればいいのでしょうか。
(CBookSecondのコンストラクタの引数にわけも分からずポインタを足したら、エラーはでなく
なりましたが、たぶん間違ってます.....)
でも、C++の知識が少ないのでもっと勉強してからお聞きすべきですね。
>親ウィンドウと子ウィンドウの関係と、クラスの継承との関係は全く違いますねー。
>その辺は、検索などで調べた方が解りやすいし、勉強になると思います。
わかりました。調べて勉強します。
>アプリケーションクラス (CBookApp) で宣言しちゃいますね。
自分としてもdairygoodsさんのおっしゃてたやりかたが、今のところ一番わかりやすいです。
CSetColorDlgの作成後、表示前にCBookDlgのthisポインタを渡してやればいいと思います。
CBookDlgクラスのメンバ関数の中で、
CSetColorDlg ScDlg;
ScDlg.pBookDlg = this; //CBookDlgクラスへのポインタを渡す
ScDlg.DoModal();
という感じでどうでしょうか。
もしかしたらポインタに関することも、もう少し調べるといいかもしれませんね。
と、僕もまだまだ知らないことだらけなので、あまり偉そうなことは言えませんが(苦笑。
僕なりのアドバイスのつもりですが、気を悪くしてしまったら、ごめんなさい。。
教えていただいたようにやってみます。thisポインタですね。たしか、C++の本で自分が斜め読
みしてたところにありました.....
とりあえず解決にチャックして、みなさんのアドバイスを自分の中で消化してみて、それでも分
からなければ、もう一度質問させて頂くことにします。
西風さん、そしてアドバイスいただいたみなさん、どうもありがとうございました。
> もし、(本当の?)グローバル変数にしたい場合には、
どこかのcppファイルに(関数の中以外)
// a.cpp
int a;
と書けば、全てグローバル変数です。
(グローバルにしたくない場合、staticを付けます)
そして、別のcppファイルで変数aを参照したければ、
// b.cpp
extern int a;
と書きます。これは、変数aを使う前であれば、
どこにでも書けます。関数の中でも書けます。
int function()
{
extern int a;
a = 5;
}
しかし、変数を参照するたびにexternを書いていたら面倒ですから、
普通は共通のヘッダーファイルに書いておくというだけの事です。