ダイアログ内のエディット・ボックスにフォーカスを移動したい

[戻る]
Baby Chicken 2009/05/17(日) 23:51:38
MFC SDIで作成しています。
メニューのイベント・ハンドラで
void CDICOMAnalyzerView::OnSearch2Words()
{
    // TODO: ここにコマンド ハンドラ コードを追加します


    CDIALOG1 dlg;
    CEdit* pBoxOne = (CEdit*)GetDlgItem(IDC_EDIT1);
    dlg.GotoDlgCtrl(pBoxOne);

としてIDC_EDIT1のエディト・ボックスに最初にフォーカスを移動しようとしているので
すが、Debug Assertion Failureとなり、どうもGotoDlgCtrlでエラーを起こすようで
す。
試みにその前でbreak point設定して、pBoxOneの値を見ると0x0000000のままです。どの
よようにすれば良いかさっぱり分かりません。宜しくお願いします。

Baby Chicken 2009/05/18(月) 00:01:33
ちなみに
GetDlgItem(IDC_EDIT1)->SetFocus()でもデバッグ・モードになってしまいます。

しま 2009/05/18(月) 00:38:31
>    CDIALOG1 dlg;
>    CEdit* pBoxOne = (CEdit*)GetDlgItem(IDC_EDIT1);
>    dlg.GotoDlgCtrl(pBoxOne);

さて、IDC_EDIT1 は CDIALOG1 にあるのでしょうか?
それとも CDICOMAnalyzerView にあるのでしょうか?

>    CEdit* pBoxOne = (CEdit*)GetDlgItem(IDC_EDIT1);
という書き方であれば CDICOMAnalizerView にあるもののようですし

>    dlg.GotoDlgCtrl(pBoxOne);
という書き方からすると dlg (つまり CDIALOG1)にあるかのようです

後、 CDIALOG dlg; と書いた場合、単にクラスの実体が生まれただけですが
このこととクラスが表そうとしている Windows の要素としてのダイアログが
生まれることとの違いは御分かりですか?

それから、あなたの開発環境についてなぜ書かないのでしょうか?
開発環境によって答え方が違ってくることがあるので必ず書きましょう

Baby Chicken 2009/05/18(月) 03:04:25
しま 様
ありがとうございます。
開発環境は Visual Studio 2008 Professional on Windows Vista Business Extremeで
す。
ICD_EDIT1はCDIALOG1にあります。実は、その両者の書き方を行ってみたのですが、両方
ともエラーとなります。
たぶんご指摘のよように
「後、 CDIALOG dlg; と書いた場合、単にクラスの実体が生まれただけですが
このこととクラスが表そうとしている Windows の要素としてのダイアログが
生まれることとの違いは御分かりですか?」ということが全く分かっていないことに起
因すると思います。
結局、GetDlgIetm()を行っても、0x00しか戻らない、というのは要素になっていないか
らだと思っているのですが、そこから先をどのようにすれば良いのか分からないので
す。申し訳ありません。

Baby Chicken 2009/05/18(月) 03:05:55
あと、
dlg.GetDlgItem(IDE_EDIT1);としても、その時点でデバッグ・モードに入ってしまいま
す。

wclrp ( 'o') 2009/05/18(月) 08:30:28
CDIALOG1内のOnInitDialogでフォーカスを移動するんじゃない。

PATIO 2009/05/18(月) 12:02:31
えーと、まず、せっかくAssertionが出ているのですから
これを利用しましょう。
何処で起こっているのか出ていると思いますから
そこを参照してみてなぜAssertionが起こっているのかを
調べます。

あと、既にしまさんが指摘されていますけれど、
CDialogクラスはウインドウをコントロールする為のクラスであって
ウインドウその物では有りません。
で、CDialogの派生クラスも同じくコントロールする為のクラスです。
派生クラスのインスタンスを作成した状態と言うのは
コントロールする為の準備が出来ただけの状態で実際には
ウインドウその物は表示されていません。
基本的にウインドウに対するコントロールはウインドウが表示されていないと
実行できません。

この辺の概念が理解できるような参考書があると良いのですけれど、
私はあいにく知りません。
どなたかよい参考書を御存知で来たら教えてあげてください。

Baby Chicken 2009/05/18(月) 20:53:18
PATIO様

ありがとうございます。Assertで何処にいくのかを見ると、GetDlgItemやGotoDlgCtrlの
中でいけないものを参照するようです。
今、
CDialog dlg;と宣言して、それが表示されるのは何時なのでしょうか?
プログラムの例を見ると
CDialog dlg;
if (dlg.DoModal() == IDOK) {
//処理する
となっていますが、これだとその何処にGetDlgItmなどを記述すれば良いのでしょうか?

もう少しヒントを頂ければありがたいのですが・・・

wclrp ( 'o') 2009/05/18(月) 21:22:08
DoModal呼ぶ前はウィンドウ(CDIALOG1とIDE_EDIT1)は存在しない。
DoModalが割った後もウィンドウは存在しない。

wclrp ( 'o') 2009/05/18(月) 21:22:44
DoModalが終わった後な

rin 2009/05/18(月) 21:26:36
親側、つまりCDICOMAnalyzerView側から操作するのではなく
子側、つまりCDIALOG1の中で操作しましょう


>if (dlg.DoModal() == IDOK) {
この「DoModal」が
「ダイアログを作成・表示、
 ダイアログ操作
 ダイアログが閉じられる
 そして結果を返す」
までを行います(そして、結果とIDOKを比較)

つまり、親側は、ダイアログ表示中には、
DoModalの結果をずっとまって固まっています

親側はずっと待ってる間は、
子であるダイアログは自分で自分を操作すればいいのです

PATIO 2009/05/19(火) 13:07:56
私がクラスで物を考えるときは、基本的にそのクラスの操作その物は
そのクラス自身にさせて外側はその為の材料を与える事と
処理の開始を支持するだけにするという風に考えます。

ですから、表示した直後にフォーカスを移動させる場合なら
外部からの処理開始すら要らなくてダイアログ自身の初期表示時に
動作するOnInitDialogで処理します。
MFCを使うのであれば、こういった様々なタイミングで動作する関数が
用意されていますから、それをうまく使って実現するのが良いと思います。

どうしても外部からの私事が必要な場合でも
ダイアログ側に必要な情報を引数でもらう様な関数を作成して
ダイアログ側でもらった引数を元に内部で処理するようにした方が
他のクラスとの関連が薄くなるのでC++言語的にも良いと思います。

この辺のC++言語としての考え方やオブジェクト指向の考え方が
分かってくると自然とどのクラスに実装するのが良さそうかが
分かってくると思います。

何にせよ、体系的な勉強が必要ですね。
漠然とプログラミングしているだけではこの辺の知識はついて来ません。

PATIO 2009/05/19(火) 13:42:54
誤字訂正。(^^;

誤)
処理の開始を支持するだけにするという風に考えます。

正)
処理の開始を指示するだけにするという風に考えます。


誤)
どうしても外部からの私事が必要な場合でも

正)
どうしても外部からの指示が必要な場合でも


うーむ、なぜに同じ熟語の間違いが違った内容になっているか。(^^;

PATIO 2009/05/19(火) 13:46:09
あと、初期表示に必要なデータはダイアログのインスタンスを
作成した後、ダイアログのDoModalを呼び出す前に
メンバー変数やメンバー関数を使ってダイアログのインスタンスに
引き渡して置くようにするのが常道だと思います。
あとは、OnInitDialogでメンバー変数を参照して初期表示をする
という流れになると思います。

Baby Chicken 2009/05/19(火) 14:09:42
[[解決]]
wclrp様、rin様、PATIO様
ご指導ありがとうございます。確かに、クラスの本質を見誤っており、ついつい昔の
BASIC的なやり方をしていました。
OnInitDialogで処理しようとしたのですが、CDialogクラスのWindows Messageには存在
しませんでした。このため、コンストラクタで処理しようとしたら、当然のように駄目
でした。結局、
void CDIALOG1::OnShowWindow(BOOL bShow, UINT nStatus)
{
    CDialog::OnShowWindow(bShow, nStatus);

    // TODO: ここにメッセージ ハンドラ コードを追加します。
    CEdit* pBoxOne = (CEdit*)GetDlgItem(IDC_EDIT1);
    GotoDlgCtrl(pBoxOne);
}
でうまくいきました。
これで宜しいでしょうか?

rin 2009/05/19(火) 14:28:31
メッセージではなく、オーバーライドにある

Baby Chicken 2009/05/19(火) 14:38:22
rin様
ありがとうございます。

古いスレッドには追加発言できません。