ダイアログが生成された「後」のイベントについて

[戻る]
あさみ 2001/05/30(水) 19:03:57
みなさん、こんばんは。あさみと申します。
VC(というより、プログラム自体)初めてです。

少しだけ勉強したことのある「VB」っぽいなー
と思って、「ダイアログベース」でプログラミングしています。

私がやりたいことは、
1.画面をまず表示する。
2.その後、メッセージボックス「ようこそ」を表示。

たったこれだけ(?)のことなのですが、
2→1は「OnInitDialog関数」内でメッセージボックスを出せばいいので
できるのですが、ではその逆は?と悩んでいる状態です。

ちなみにDoModalで画面をよんでいます。

画面が作られた直後のイベント
「OnExitDialog関数」(名づけるとしたら、ですが)
みたいなものは、あるのでしょうか?

もし、あるとしたら教えてください。

よろしくお願いします。

ku 2001/05/30(水) 21:55:44
SDIかMDIならOnCloseを処理すればよいのでしょうが
ダイアログだとOnCloseを通らないルートがあるので
気を付けなければなりません。

初期のダイアログでは「OK」ボタンと「キャンセル」ボタンと
「×」でダイアログを閉じます。ダイアログの左上のアイコンでマウスクリックして
「閉じる」を選んでも「×」と同じ動作をします。

「×」は結局はOnCloseで処理できます。
「OK」ボタンはOnOK、「キャンセル」ボタンはOnCancelです。
ここの3箇所で終了処理の共通関数を呼ぶようにすれば良いのではないでしょうか。
ダイアログが見えなくなった後に来るメッセージでも良ければ
WM_DESTROYで処理できなくもないけど、おそらくイメージしているのとは違うと思います。

あさみ 2001/05/31(木) 09:18:30
kuさん、お答えくださり、本当にありがとうございます。

最初の質問の時、「OnExitDialog関数」と、
変に混乱させるようなことを書いてしまい、
申し訳ありません。

具体的にやりたいことは、こういうことです。

(1)画面を表示する。
(2)「表示された後で」長いループで画面のコントロールに初期値を入れる。

なぜこんな処理にしたいかというと、
ある画面から、ある画面に移るとき、
ダイアログAを閉じ、ダイアログBを開く間に
(2)のループでたくさん時間がかかってしまうと、
「あれ?終わったの?」
と思われてしまうほど(2)が長いので、
一応画面だけでもだしたいな、と思ってるんです。


「画面を閉じるとき」のイベントではなく、
「表示された直後」のイベントをとりたいな、
と思ってるんですが、そんなイベントはないのでしょうか?

もし、イベント自体が存在しなくても、何がしかの
アイデア等ございましたら、
アドバイスいただけないでしょうか。

よろしくお願いします。

ku 2001/05/31(木) 09:50:45
構造はこんな感じでしょうか?
メインウィンドウ−−1.画面Aを表示
         −2.画面Aを閉じる
         −3.ループ
         −4.画面Bを表示
しかし、このままだとループが終わるまで画面Bを表示することは不可能ですね

モードレスダイアログで処理中の状況を表示した方が良いのではないでしょうか?
メインウィンドウ−−1.画面Aを表示
         −2.画面Aを閉じる
         −3.モードレスの処理中画面開始
         −4.ループ
         −5.モードレスの処理中画面終了
         −6.画面Bを表示

当初の質問の答えとしては
OnInitDialogで自分自身にユーザメッセージをPostMessageし
そのユーザメッセージを処理をすれば
OnExitDialog関数にあたる処理になると思われます。

あさみ 2001/05/31(木) 10:39:08
kuさん、いつもありがとうございます。

>当初の質問の答えとしては
>OnInitDialogで自分自身にユーザメッセージをPostMessageし
>そのユーザメッセージを処理をすれば
>OnExitDialog関数にあたる処理になると思われます。

kuさんの方法ってこういうことなのかな?と、勝手に解釈して、
下のようにやってみました。

OnInitDialog関数の中にPostMessageでメッセージ「999」
をメッセージとしておくり、それをDefWindowProc関数内で
if(message==999)という判定をし、その中でループを行うと、
できそうです(当初のメッセージボックスは画面生成後、表示できました)。
(このやり方でホントにいいのかな?メッセージの取得とか、
 あんまりわかってないので…)
kuさん、ありがとうございます。


>モードレスダイアログで処理中の状況を表示した方が良いのではないでしょうか?

そうですね、確かに。
画面表示と同時に「処理中」という小さいダイアログを
表示すれば、「ああ、今処理中なんだな」ってわかりますもんね。

モードレスダイアログは、一度作ってみようと思って挫折したのですが、
作り方として根本的にまちがってるのかな?

前に作ったのは

(1)ダイアログを設定(リソースID:IDD_DLG1)
(2)CDialogクラスを新規追加。(クラス名をCDlg1とします)
(3)メインの処理から以下の記述でダイアログを呼び出す。
   CDlg1 dlg;
      dlg.Create("IDD_DLG1"); 
      dlg.ShowWindow(SW_SHOW);

というものですが、実行時エラーになります。
何か指定がたりないとか、お気づきの点ございましたら、
ご指摘ください。よろしくお願いします。

ku 2001/05/31(木) 13:02:21
DefWindowProcよりWindowProcの方が多少マシな気がしますが
どちらにしろ、これを使うのはテストのときのみか
できるだけ使わない方が良いと思います。

ユーザメッセージの番号を適当な値にしてはいけません。
仮にWM_ONINITDIALOGが999だとしたら、うまく動作しなくなるからです。
(WM_USER + ???)とヘッダで定義しておくのが良いと思います。
プラスする値もMFCを使う場合は幾つ以上が良いってのが、
何かのヘルプに書いてあったような気もしますがそれは忘れてしまいました(^^;
まー、重ならないように適当な値で。

1.まず、ダイアログクラスのヘッダ、ユーザメッセージを追加します。
#define WM_USER_999                    (WM_USER + 999)

2.クラス定義にユーザメッセージハンドラのプロトタイプ宣言を追加します。
class CXXXDlg : public CDialog
{
protected:
    afx_msg LONG WmUserProc999(UINT wParam, LONG lParam);

3.ダイアログクラスのソースのメッセージマップにWmUserProc999を追加します。
BEGIN_MESSAGE_MAP(CXXXDlg, CDialog)
    //{{AFX_MSG_MAP(CXXXDlg)
    ON_WM_SYSCOMMAND()
    ... 省略 ...
    //}}AFX_MSG_MAP
    ON_MESSAGE(WM_USER_999, WmUserProc999)
END_MESSAGE_MAP()

4.ダイアログクラスのソースにユーザメッセージハンドラ関数を追加する。
LRESULT CXXXXDlg::WmUserProc999(UINT wParam, LONG lParam)
{
    MessageBox("test");
    return 0;
}

ku 2001/05/31(木) 13:25:41
DefWindowProcやWindowProcは使ってはいけないのではなく
メッセージハンドラとして定義されているものが見つかれば
なるべくそちらを使った方が良いという意味です。

モードレスは下記のようにして使ってます。

1.ダイアログのヘッダにCreat関数を追加します。
public:
    BOOL Create(CWnd* pParent)
    {
        BOOL fRet = CDialog::Create(CMyDlg::IDD, pParent);
        if (fRet) {
            ShowWindow(SW_SHOW);
        }
        return fRet;
    }
2.CFrameWndの派生クラス(CMainFrame)のメンバ変数を追加し初期化します。
CMyDlg* m_pDlg = NULL;
3.CFrameWndの派生クラス(CMainFrame)のOnCreateにコードを追加します。
  関数の終わりの方がいいです。
    m_pDlg = new CMyDlg(this);
    if (m_pDlg) {
        m_pDlg->Create(this);
    }
4.CFrameWndの派生クラス(CMainFrame)のOnCloseにモードレスダイアログを破棄
  するコードを追加します。
void CMainFrame::OnClose() 
{
    if (m_pDlg) {
        m_pDlg->DestroyWindow();
        m_pDlg = NULL;
    }
    CFrameWnd::OnClose();
}
5.ダイアログクラスでEndDialogとかで終了するのは良くないので
  OnOK()やOnCancel()やOnClose()をうまく処理する必要がありますね。
  GetParent()->PostMessage(WM_USER_???)などとやり
  CMainFrameの方で
    if (m_pDlg) {
        m_pDlg->DestroyWindow();
        m_pDlg = NULL;
    }
  とやるようなユーザメッセージ関数を追加した方がよいと思います。

あさみ 2001/05/31(木) 14:22:31
[[解決]]
kuさん、とてもわかりやすい回答、
本当にありがとうございます。

メッセージの送り受けについては、
確かにどんな値を指定すれば他のメッセージと
ぶつからないか、分からないまま「999」という
適当な値を指定していたのですが、
「WM_USER」という便利な値があったんですね。
知識が浅いなあ、わたしって…。

メッセージを受ける側でも、
「WM_USER+999」を受け取ったとき初めて呼び出される
関数を定義したほうが良い、ということですよね?
(DefWindowProc内でメッセージ値の判定をしないと、
 延々メッセージボックスが表示されつづけるところをみると
 どんなメッセージが送られても、DefWindowProc関数は
 動いてるのかな?と思いました。)


モードレスのダイアログについては、
びっくりしました!
こんなに手順が必要なんですね…。

ダイアログのヘッダファイル〜ダイアログのクリエイトまで、
kuさんに教わった手順を踏んでやってみたところ、
モードレスのダイアログが表示できました!

今まで、モードレスダイアログの作り方が分からず、
避けてきたのですが、やっぱり「非同期で動く」というのは
すごく便利がいいので、とても勉強になりました。


kuさん、わたしはとても素人なのですが、
そんなわたしでも分かりやすいお返事、
本当にありがとうございました。

これからも、よろしくお願いします。

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