#pragma twice

KAB-studio > プログラミング > #pragma twice > 048 Version 3.23 オーバーライド

#pragma twice 048 Version 3.23 オーバーライド

前のページへ 表紙・目次へ 次のページへ

 Version 3.23
オーバーライド

前回までに、ダイアログを表示したときに【Ans】の中に前の結果を入れ
ておく、って機能を CCalcDlg に移す、っていうことをしました
ってことは、残るは【OK】ボタンを押したとき、だね
そゆこと。さて、ボタンを押したとき、って言ったらどんな感じだと思
う?
そりゃやっぱり、【=】ボタンが押したときに CCalcDlg::OnBEqual() が
呼ばれる、みたいな感じなんじゃないかな
その通り。で、そのときはどうしたんだっけ
えーっと、かなり昔だよね
そう、かなり昔…… Ver 2.0 ( No.011 )だね
でもまだ1年経ってないんだ
これ入れてあと3回で1周年。ま、それは置いといて、もう一度復習を兼
ねて〈イベントハンドラ〉の作り方を見てみましょう
あ、こういうのもイベントハンドラって言うんだ
さて、まずダイアログエディタで Calc ダイアログ表示して
 ResourceView で IDD_CALC_DIALOG をダブルクリックと
そしたら【OK】ボタンの右クリックメニューから
【イベント】でしょ!
そう。それを選ぶと
 【クラス CCalcDlg 用の Windows メッセージおよびイベント ハンドラの
新規作成】というダイアログが表示される。
左側が BN_CLICKED に、右下が IDOK になってることを確認して
あ、そういえば BN_CLICKED ってなに?
うーん、まだ早いような……
とりあえずおせーて
そうだね、たとえばボタンが押されたときとかのイベントは、ウィンドウ
ズが管理してます
ってことは API とかってこと?
うん、そういうレベルでサポートされてるってこと。で、実際にボタンを
押すと、ウィンドウズからアプリケーションに BN_CLICKED っていう〈メッ
セージ〉が送られてきます
めっせーじ?
ま、〈ボタンを押したぞ!〉って声、みたいなもんだね。このほかにも、
イベントの数だけメッセージがあって、 MFC を使わないときにはこのメッ
セージをかなり憶えておかないとちょっときつかったり……
へー、そーゆーのも MFC 使うと楽できるんだ
でもここで BN_CLICKED 知らないとまずかったりとか、 MFC があれば全
然OKってわけでもないんだけどね。ま、ようするにこれから憶えることが
たくさんあるってことで
む〜
で、右下の IDOK はボタンの ID ね
それはわかる。で、【追加と編集】ボタンを押せばいいんでしょ?
そゆこと
 ボタンを押すと【メンバ関数の追加】ダイアログが表示される。
メンバ関数名、 OnOK() 。このまんまで?
このまんまで
んじゃまんま。……あれ、 OnOK() ってどっかで……
 OK ボタンを押すと CalcDlg.cpp が表示される。

void CCalcDlg::OnOK() 
{
    // TODO: この位置にその他の検証用のコードを追加してください
    
    CDialog::OnOK();
}

あ、こんなところにも TODO が
さて、【OK】ボタンを押したらこの関数が呼ばれるってことを確認したい
とき、どうするんだっけ?
えっと、 TRACE() 置くとか、ブレークポイント設置するとか?
そうそう。今回はブレークポイントの方を使ってみて
はーい。んじゃ TODO を
ちょいまち、ブレークポイントは〈プログラムのある行〉じゃないと。だ
からコメントの上じゃダメ
へーそうなんだ。じゃー CDialog::OnOK() をクリックして、手のひらボ
タンを押して
 行の左に丸が表れる。
んじゃビルドして実行、【OK】ボタンをクリック!
 丸の上に右向き矢印が表れ、アプリケーションが停止する。
止まったから、やっぱ【OK】ボタン押すとこれ呼ばれるんだ
じゃ続いて、 CDialog::OnOK() の中に入ってみて
あら予想外の展開。んじゃ中カッコに入るボタンっと
 Dlgcore.cpp ファイルが表示される。
あ、 CDialog のメンバ関数だから、 MFC のプログラムのファイルが表示
されたんだね。……あれ?
 CDialog::OnOK() が表示されている。
これって、前に一度見たことない?
あるよ、 Ver 3.17 ( No.042 )で。あのときはダイアログを閉じるんで
そうそう、ダイアログを閉じるのは EndDialog() っていうので、その引
数が DoModal() の戻り値になる、とかやったよね、うんうん
さて、考えてみましょう
はい?
【OK】ボタンを押したときに呼ばれたのは?
 CCalcDlg::OnOK() だよ
じゃあ CDialog::OnOK() は?
……そういえば、 CDialog::OnOK(); っていう行が  CCalcDlg::OnOK() 
の中にあって、そこに入ったら……
じゃ、実験。この行をコメントアウトしてみて
ってことは

void CCalcDlg::OnOK() 
{
//  CDialog::OnOK();
}

って感じ?
そんな感じ
じゃビルドして実行……あーっ、【OK】ボタン押してもダイアログ閉じな
いー!!
そういうことになります。つまり……どしたの?
どうやってダイアログ閉じればいいのぉ?
【キャンセル】ボタンは効くでしょ
あ、そっか
で、どういうことだと思う?
つまり、 CDialog::OnOK(); って行では、 CDialog クラスの OnOK() メ
ンバ関数を呼んでるってことなんだ
それはつまり、 CDialog と CCalcDlg の両方に OnOK() メンバ関数があ
るってことだよね
あそうか! で、 CDialog::OnOK() ひとつだったときにはこれが呼ばれ
て、 CCalcDlg::OnOK() ができたらこの新しい方が呼ばれるようになった
重要なのは、かたっぽしか呼ばれないってこと
つまりわざわざ CDialog::OnOK(); ってしないと呼ばれないんだ
こういうシステムを〈オーバーライド〉っていいます
おーばーらいど?
そう。まず、 MFC の方に【OK】ボタンを押したとき用のイベントハンド
ラ CDialog::OnOK() を用意しておきます
うんうん
このメンバ関数にはダイアログを閉じる機能を入れておきます
そうすれば、ダイアログに IDOK のボタンを置くと、そのボタンを押す
だけでこのメンバ関数が呼ばれてダイアログが閉じる、って仕組みなんだ
よね
そうそう。これって簡単でしょ
うん、簡単
でも、今回みたいに〈【OK】ボタンを押したときに独自の処理をしたい〉
っていう場合があるでしょ
そういうときに、 CCalcDlg::OnOK() を作る!
継承したクラスで、同じ名前のメンバ関数を作ると、新しく作った方が優
先的に呼ばれる仕組みになっているわけ
それがオーバーライド?
そういうこと。あと〈 OnOK() を CCalcDlg クラスでオーバーライドする〉
みたいに使う時もあるかな
へー。あ、もしかしてこの辺って、前に話してた〈カスタマイズクラス〉
とかと関係ある?
もちろん。 MFC にある機能を使いながら、そのアプリケーション専用の
機能を組み込む。そのために
 MFC のクラスから継承した新しいクラスを作って、こんなふうにオー
バーライドすればいいんだ
ま、これは思いっきり簡単な例だけどね。あ、今のコメントアウト取り除
いておいてね
はーい。で、【OK】ボタンのをここに書き込むんでしょ?
そうそう。これまでの知識があればできるはずだけど……
やってみる!! えっと、まず CCalcApp::InitInstance() の中で……

    if (nResponse == IDOK)
    {
        WriteProfileInt( cDialogStr, cAnsStr, dlg.m_iAns );
    }

この WriteProfileInt() を切って貼っつけちゃえばいいんだから……

void CCalcDlg::OnOK() 
{
    WriteProfileInt( cDialogStr, cAnsStr, dlg.m_iAns );
    
    CDialog::OnOK();
}

で……どうしよ
ひとつずつひとつずつ
はぁい。じゃ、最後の m_iAns から。ここは CCalcDlg 、ううん dlg の
中なんだから、 dlg. はいらないから……

    WriteProfileInt( cDialogStr, cAnsStr, m_iAns );

 cDialogStr と cAnsStr は CCalcApp::InitInstance() の中で作ってた
んだよね。あれを……カットしちゃっていい?
うん、大丈夫。もう CCalcApp::InitInstance() の中じゃ使ってないから

じゃ……

void CCalcDlg::OnOK() 
{
    CString cDialogStr;
    cDialogStr.LoadString( IDS_REG_DIALOG );
    CString cAnsStr;
    cAnsStr.LoadString( IDS_REG_ANS );

    WriteProfileInt( cDialogStr, cAnsStr, m_iAns );
    
    CDialog::OnOK();
}

最後に、前回作った GetTheApp() を使って……
あ、あと UpdateData( TRUE ) も呼んでおいて。そうしないと m_iAns の
中に値が入ってないから
じゃっ!

void CCalcDlg::OnOK() 
{
    UpdateData( TRUE );
    CString cDialogStr;
    cDialogStr.LoadString( IDS_REG_DIALOG );
    CString cAnsStr;
    cAnsStr.LoadString( IDS_REG_ANS );

    GetTheApp().WriteProfileInt( cDialogStr, cAnsStr, m_iAns );
    
    CDialog::OnOK();
}

どう? どうよ、これで!
OK!
じゃ、ビルドして実行、計算して、【OK】ボタン押して閉じて、もう一度
実行……やたっ、同じのが【Ans】に入ってる!
うん、大丈夫そうだね
でもなんで今度は UpdateData() 必要なの? CCalcDlg::OnInitDialog()
のときもそうだったよね
呼ばないで済んだのは CDialog::OnOK() の中で呼んでくれてたから。も
う一度 CDialog::OnOK() の中見てみ?
あ、ホントだ、呼んでる
同じく CCalcDlg::OnInitDialog() の方じゃ、 CDialog::OnInitDialog() 
の方で呼んでくれてたってこと
なるほど。ってことはさ、

void CCalcDlg::OnOK() 
{
    CDialog::OnOK();

    CString cDialogStr;
    cDialogStr.LoadString( IDS_REG_DIALOG );
    CString cAnsStr;
    cAnsStr.LoadString( IDS_REG_ANS );

    GetTheApp().WriteProfileInt( cDialogStr, cAnsStr, m_iAns ); 
}

なんてのはどう?
それもOK!

/*
    Preview Next Story!
*/
そういえば、あと2回?
あと2回で1周年。Ver 3 もそこで終了
って、 Ver 3 って半年近くやってるんだね
それだけ、重要な話が詰まってたってことだね
無駄なとこも多かったような……
というわけで次回
< Version 3.24 デバッグビルドとリリースビルド >
につづく!!
 Ver 4 からは細かい話
って、あと2回もしっかり頼むよー
はいはい
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。