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 となります
}
>「x.Create(this);」だとモードレスなのですが、内容が表示されません。(モードレス
ダイアログに設定済みということです)
内容が表示されないとは、どういう状態ですか?
・ダイアログが表示されないか、表示されるがすぐに消えてしまう。
・ダイアログは表示されるが、リストボックスが空になっている。
前者であれば、OnKakikomi関数終了時にObが破棄されるためです。
モーダルの時には、ダイアログが閉じるまでOnKakikomi関数は終了しませんが、
モードレスでは、通常すぐに終了してしまいます。
>内容が表示されないとは、どういう状態ですか?
>「・ダイアログは表示されるが、リストボックスが空になっている。」
後者の方です。
内容というより値と言ったほうが良かったですね。
すいません。
ダイアログBが「書き込みボタン」を押す前に表示されていませんか?
>ダイアログBが「書き込みボタン」を押す前に表示されていませんか?
表示されていません。
提示のソースで 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 さんもこのこと懸念しているのだと思います。)
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 クラスのインスタンスとは別インスタンスによるダイアログが
>表示されているのかも知れません。
この可能性があるのであれば、錯覚ではなかったようです。
実行すると、リストボックスに一瞬表示されているようです。
「ドラッグ移動」は出来ます。データの受け渡しなども問題ないようです。
一瞬表示されているのであれば、別インスタンスが問題であると考えて良いのでしょうか?
以下のようにしてみてください。たくさんの推論を含んでいますので、上手くいかなくても
文句を言わないでください。
(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);
済みません。リストボックスへの追加処理を Ob::OnInitDialog でやっていたのを忘れて
ました。以下のようにしてみてください。
変更後
// a = memo;
m_pOb->GetDlgItem(IDC_LIST1)->AddString(memo);
// UpdateData(FALSE);
m_pOb->UpdateData(FALSE);
上記は Ob クラスのメンバ関数とすべきですね。
また、Ob::OnInitDialog の中のリストボックスに関する処理は不要になりますね。
WIZさん、お返事ありがとうございます。
>上記は Ob クラスのメンバ関数とすべきですね。
すいません、ちょっと理解できないでいます。
何をObクラスのメンバ関数にすべきなのでしょうか?
> Ob x;
> x.a=memo;
> x.Create();
の部分を
>m_pTest->GetDlgItem(IDC_LIST1)->AddString(memo);
>m_pTest->UpdateData(FALSE);
に変更しました。
以下のエラーが発生しています。
「'AddString' : 'CWnd' のメンバではありません。」
お忙しい中、よろしくお願いします。
>> 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);
....
}
WIZさん、ご説明ありがとうございます。
ご説明のとおりにしましたが、アプリケーションエラーが発生します。
「…メモリがreadになることはできません」
> Ob x;
> x.a=memo;
> x.Create();
としていましたが、a以外にもbがありダイアログは3つあります。
今回はAとBとのデータ渡しですが、ご説明いただいたコードだと「どのダイアログなのか」
というところが引っかかっているのではないかと思います。
お手数とご迷惑をおかけしますが、よろしくお願いします。
>?としていましたが、a以外にもbがありダイアログは3つあります。
>今回はAとBとのデータ渡しですが、ご説明いただいたコードだと「どのダイアログなのか」
>というところが引っかかっているのではないかと思います。
aのかわりに「m_pTest」を使っているのですね。
上の発言は無かったことにしてください。
>((CListBox*)(m_pTest->GetDlgItem(IDC_LIST1)))->AddString(memo);
上の所でブレークポイントを張ってデバックすると、以下のようなメッセージが出てきます
「ハンドルされていない例外は○○.exeにあります」
初めて見たので、これがアプリケーションエラーの原因かわかりませんが、お伝えします。
>> ((CListBox*)(m_pTest->GetDlgItem(IDC_LIST1)))->AddString(memo);
> 上の所でブレークポイントを張ってデバックすると、以下のようなメッセージが出てきます
> 「ハンドルされていない例外は○○.exeにあります」
> 初めて見たので、これがアプリケーションエラーの原因かわかりませんが、お伝えします。
おそらく m_pTest の値が不正なためでしょう。
m_pTest は CWnd* or CDialog* or 派生クラスのポインタ型だと思いますが、
GetDlgItem を使用する前に、目的のダイアログのインスタンスをポイントするように
設定していますか?