ダイアログ間データ表示

[戻る]
Yamabuki 2005/05/09(月) 11:29:16
VC++初心者です。
開発環境は Win2000  VC++6.0 SP6  MFC(exe)ダイアログベースです。

ダイアログAにEditBoxがあり、値を書き込み「書き込みボタン」を押すと、ダイアログBのリス
トボックスに値が表示されるようにしたいです。
モードレスダイアログです。

「x.Create();」にしていますが、「x.DoModal();」だと内容を表示することが出来ます。
これだとモーダルになってしまいます。
「x.Create(this);」だとモードレスなのですが、内容が表示されません。(モードレスダイア
ログに設定済みということです)
「x.Create();」だと「 'Create' : 関数が不正な 0 個の実引数をともなって呼び出されまし
た。」というエラーが発生します。

モードレスで値を表示するにはどうすればよいのでしょうか?
それとも今のやりかたでは基本から違うのでしょうか?
どなたか教えていただけないでしょうか?
よろしくお願いします。

下記がコードです。

void CPreviewDlg::OnKakikomi() 
{
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください

// データをobに送る-------------------------------------
    CString memo;
    CEdit *p;
    
    p=(CEdit *)GetDlgItem(IDC_EDIT1); //エディットボックスから受け取り

    p->GetWindowText(memo);
    Ob x;
    x.a=memo;
    x.Create();   ←エラー発生場所



BOOL Ob::OnInitDialog() 
{
    CDialog::OnInitDialog();
    
    // TODO: この位置に初期化の補足処理を追加してください
    //リスト表示--------------------------------------------------------
    CListBox *q;
    q=(CListBox *)GetDlgItem(IDC_LIST1);
    q->AddString(a);

    return TRUE;  // コントロールにフォーカスを設定しないとき、戻り値は TRUE 
となります
                  // 例外: OCX プロパティ ページの戻り値は FALSE となります
}

REE 2005/05/09(月) 12:09:32
>「x.Create(this);」だとモードレスなのですが、内容が表示されません。(モードレス
ダイアログに設定済みということです)

内容が表示されないとは、どういう状態ですか?
・ダイアログが表示されないか、表示されるがすぐに消えてしまう。
・ダイアログは表示されるが、リストボックスが空になっている。

前者であれば、OnKakikomi関数終了時にObが破棄されるためです。
モーダルの時には、ダイアログが閉じるまでOnKakikomi関数は終了しませんが、
モードレスでは、通常すぐに終了してしまいます。

Yamabuki 2005/05/09(月) 12:17:10
>内容が表示されないとは、どういう状態ですか?
>「・ダイアログは表示されるが、リストボックスが空になっている。」
後者の方です。
内容というより値と言ったほうが良かったですね。
すいません。

REE 2005/05/09(月) 13:21:00
ダイアログBが「書き込みボタン」を押す前に表示されていませんか?

Yamabuki 2005/05/09(月) 14:00:48
>ダイアログBが「書き込みボタン」を押す前に表示されていませんか?
表示されていません。

WIZ [E-Mail] 2005/05/09(月) 17:01:31
提示のソースで x.Create(this); でコンパイルできるということは、
Ob クラスには CPreviewDlg* 型(またはスーパクラスだと思われる CDialog*/CWnd* 型)
の第 1 引数を持つ Create 関数が存在するということですね。
このようなプロトタイプの関数は CDialog/CWnd クラスには存在しないので、
この Create 関数は Yamabuki さんが自分で実装した関数ですよね?

それで、先ず Ob::Create 関数の実装を提示してください。

次に、REE さん質問に対する回答

>> 内容が表示されないとは、どういう状態ですか?
>> 「・ダイアログは表示されるが、リストボックスが空になっている。」
> 後者の方です。
>
>> ダイアログBが「書き込みボタン」を押す前に表示されていませんか?
> 表示されていません。

が事実ならば、データの受け渡しが上手くいっていないのでしょう。
Ob::OnInitDialog 内にブレークポイントを張って、Ob::OnInitDialog が
コールされているか、Ob::a にデータが設定されているか、CListBox::AddString
が正常終了しているか一つ一つ確認していってください。

後、表示されている Ob クラスのダイアログをマウスでドラッグして移動とか
できますか?もしできないとか、マウスでなぞると一部消えてしまうとかなら、
それは残骸で Ob クラスのインスタンスは破棄されているものと思います。
もしドラッグ移動できるなら、CPreviewDlg::OnKakikomi でローカル変数として
構築された Ob クラスのインスタンスとは別インスタンスによるダイアログが
表示されているのかも知れません。
(多分 REE さんもこのこと懸念しているのだと思います。)

Yamabuki 2005/05/09(月) 18:28:53
WIZさん、教えていただきありがとうございます。

>Ob::Create 関数の実装を提示してください。

BOOL Ob::Create(CWnd *pWnd)
{
    m_pParent = pWnd;
    BOOL bret = 
        CDialog::Create( Ob::IDD, m_pParent);
    if( bret != 0)
    {
        this->ShowWindow( SW_SHOW);
    }
    return bret;

}

>構築された Ob クラスのインスタンスとは別インスタンスによるダイアログが
>表示されているのかも知れません。
この可能性があるのであれば、錯覚ではなかったようです。
実行すると、リストボックスに一瞬表示されているようです。

「ドラッグ移動」は出来ます。データの受け渡しなども問題ないようです。

一瞬表示されているのであれば、別インスタンスが問題であると考えて良いのでしょうか?

WIZ [E-Mail] 2005/05/09(月) 19:39:13
以下のようにしてみてください。たくさんの推論を含んでいますので、上手くいかなくても
文句を言わないでください。

(1) プロジェクトのソース全体を grep して、Ob クラスのインスタンスを生成している
   場所を特定してください。
   VC6 ならばメニューの [編集] - [ファイルから検索] で grep できます。
   例えば以下の様なコードが見つかったとします。(変数名は適当です)
     Ob* pOb = new Ob;
     pOb->Create(this);
   pOb に該当する変数を、CPreviewDlg クラスのメンバ変数 m_pOb にします。

(2) CPreviewDlg::OnKakikomi 内のローカル変数 Ob x に関する処理を全て m_pOb に
   関する処理に変更します。但し、ローカル変数 Ob x の宣言と Create の呼び出しは
   削除します。m_pOb->a = memo; の後に、UpdateData(FALSE); を追加します。

変更前
>   Ob x;
>   x.a=memo;
>   x.Create();

変更後
    m_pOb->a = memo;
    UpdateData(FALSE);

WIZ [E-Mail] 2005/05/09(月) 19:46:42
済みません。リストボックスへの追加処理を Ob::OnInitDialog でやっていたのを忘れて
ました。以下のようにしてみてください。

変更後
//    a = memo;
    m_pOb->GetDlgItem(IDC_LIST1)->AddString(memo);
//    UpdateData(FALSE);
    m_pOb->UpdateData(FALSE);

上記は Ob クラスのメンバ関数とすべきですね。
また、Ob::OnInitDialog の中のリストボックスに関する処理は不要になりますね。

Yamabuki 2005/05/10(火) 10:07:57
WIZさん、お返事ありがとうございます。

>上記は Ob クラスのメンバ関数とすべきですね。
すいません、ちょっと理解できないでいます。
何をObクラスのメンバ関数にすべきなのでしょうか?

>   Ob x;
>   x.a=memo;
>   x.Create();
の部分を
>m_pTest->GetDlgItem(IDC_LIST1)->AddString(memo);
>m_pTest->UpdateData(FALSE);
に変更しました。
以下のエラーが発生しています。
「'AddString' : 'CWnd' のメンバではありません。」

お忙しい中、よろしくお願いします。

WIZ [E-Mail] 2005/05/10(火) 13:35:48
>> m_pTest->GetDlgItem(IDC_LIST1)->AddString(memo);
>> m_pTest->UpdateData(FALSE);
> に変更しました。
> 以下のエラーが発生しています。
> 「'AddString' : 'CWnd' のメンバではありません

コンパイラのエラーメッセージの通りです。
GetDlgItem 関数の戻り値を CListBox 型にキャストする必要があります。
以下のようにしてみてください。

((CListBox*)(m_pTest->GetDlgItem(IDC_LIST1)))->AddString(memo);

> すいません、ちょっと理解できないでいます。
> 何をObクラスのメンバ関数にすべきなのでしょうか?

GetDlgItem + UpdateData のような処理です。
このようなコードを CPreviewDlg クラスにさらけ出してしまうことは、
クラスのカプセル化に反し、保守性の低いコードになります。

例えば、以下のようにしてみてください。(エラー処理は省いています)
class Ob: public CDialog {
    ....;
public:
    void SetData(const CString& s);
    ....;
};

void Ob::SetData(const CString& s) {
    GetDlgItem(IDC_LIST1)->AddString(s);
    UpdateData(FALSE);
}

void CPreviewDlg::OnKakikomi() 
{
    CString memo;
    ((CEdit*)GetDlgItem(IDC_EDIT1))->GetWindowText(memo);
    m_pTest->SetData(memo);
    ....
}

Yamabuki 2005/05/10(火) 15:15:46
WIZさん、ご説明ありがとうございます。

ご説明のとおりにしましたが、アプリケーションエラーが発生します。
「…メモリが"read"になることはできません」

>   Ob x;
>   x.a=memo;
>   x.Create();
としていましたが、a以外にもbがありダイアログは3つあります。
今回はAとBとのデータ渡しですが、ご説明いただいたコードだと「どのダイアログなのか」
というところが引っかかっているのではないかと思います。

お手数とご迷惑をおかけしますが、よろしくお願いします。

Yamabuki 2005/05/10(火) 16:05:38
>?としていましたが、a以外にもbがありダイアログは3つあります。
>今回はAとBとのデータ渡しですが、ご説明いただいたコードだと「どのダイアログなのか」
>というところが引っかかっているのではないかと思います。

aのかわりに「m_pTest」を使っているのですね。
上の発言は無かったことにしてください。

Yamabuki 2005/05/10(火) 18:06:03
>((CListBox*)(m_pTest->GetDlgItem(IDC_LIST1)))->AddString(memo);

上の所でブレークポイントを張ってデバックすると、以下のようなメッセージが出てきます
「ハンドルされていない例外は○○.exeにあります」
初めて見たので、これがアプリケーションエラーの原因かわかりませんが、お伝えします。

WIZ [E-Mail] 2005/05/10(火) 20:38:14
>> ((CListBox*)(m_pTest->GetDlgItem(IDC_LIST1)))->AddString(memo);
> 上の所でブレークポイントを張ってデバックすると、以下のようなメッセージが出てきます
> 「ハンドルされていない例外は○○.exeにあります」
> 初めて見たので、これがアプリケーションエラーの原因かわかりませんが、お伝えします。

おそらく m_pTest の値が不正なためでしょう。
m_pTest は CWnd* or CDialog* or 派生クラスのポインタ型だと思いますが、
GetDlgItem を使用する前に、目的のダイアログのインスタンスをポイントするように
設定していますか?

Yamabuki 2005/05/11(水) 09:58:45
[[解決]]
WIZさん、お付き合いいただきありがとうございました。
無事、表示することができました。
丁寧に教えていただき感謝しております。

>GetDlgItem を使用する前に、目的のダイアログのインスタンスをポイントするように
>設定していますか?
GetDlgItemを使用する前ではなく、後に設定していたのが問題でした。

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