#pragma twice

KAB-studio > プログラミング > #pragma twice > 091 Version 5.26 コントロールをゲットしよう!

#pragma twice 091 Version 5.26 コントロールをゲットしよう!

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

 Version 5.26
コントロールをゲットしよう!

コントロール編もいよいよ大詰め!
いつの間にそんなシリーズが? ってゆーかもう26回……
あと10回は続くかも
げげ
さて、前回は新しくボタンを作ってみました
そーそー
今回は、逆にすでにあるコントロールを操作してみましょう
? だって、 m_cDataLstBox みたいにクラスウィザード使えば
じゃあ使わない場合
……できんの? そんなこと
もちろん。前も言ったけど、得体のしれないものも
ちゃんとプログラムで実現できる! そりゃアプリもプログラムだからそ
うなんだろうけど……
じゃ、試してみようか

// いつものメンバ関数。
void CFileTestDlg::OnBtnShow() 
{
    CListBox *pcListBox
        = (CListBox *)GetDlgItem( IDC_LST_DATA );
    pcListBox->AddString( "あいうえお" );
    return;
//  あとは取っておきましょう。

ん? なんか複雑だけど、でも AddString() って使ったのだよね
そう、リストボックスに追加するメンバ関数。じゃ、最初から見ていきま
しょう
最初はポインタ作ってるね
そう、 CListBox のポインタ。このポインタで受け取ってるのは?
 GetDlgItem() の戻り値。 API のかな、 MFC のメンバ関数かな
こういう類の関数は、 API だとたいがい最初にウィンドウハンドルを渡
すから
そういえば前回の ShowWindow() もそうだね。ってことは MFC のメンバ
関数なんだ。 MSDN …… CWnd::GetDlgItem() ね。 CDialog のじゃないん

基本的には、ダイアログじゃなくてもコントロールは貼り付けられるから

で、引数は……リストボックスの ID だね。戻り値は、そのコントロール
の CWnd ポインタなんだ
えーっと、コントロールは全部ウィンドウだって言ったよね
うん聞いた
じゃ、そのページの下の方の【階層図】っていうの見て
ほいクリック。なんか大きな画像が出てきた……でもちょっと見にくい

印刷したのがパッケージに入ってるから普通はそっち見ればいいんだけど
あたし見れないもん……
で、中段左端に
 CWnd あるね
この図は継承関係を表してて、下のクラスは上のクラスから派生してる
っていうのを示してます
そっか、これ見れば CDialog が CWnd から継承してるって分かるんだね
で、下段中央に
コントロール、 CButton とか CListBox とか。つまりこういうのも全部 
CWnd から継承してるんだ
まとめるね。コントロールはウィンドウの一種
だからコントロールのクラスは CWnd から派生してるんだ
そうすれば CWnd の機能はそのまま使えるからね。コントロールもウィン
ドウだからウィンドウハンドルを持ってて、それを CWnd が管理するから
だから CDialog::GetDlgItem() の戻り値の CWnd * を CListBox * にキャ
ストしちゃっていいんだ
……よくない
へ?
ま、 MSDN に〈していい〉って書いてあるし、してるサンプルコードが多
いから大丈夫なんだろうけど、ホントはこれはしちゃダメ
そうなの?
そう。さっきの図で、 CWnd の下に CListBox があるでしょ
うん、そりゃ CWnd から CListBox が派生されてるんだから
この、上のクラスのポインタから、下のクラスのポインタに無理矢理キャ
ストすることを〈ダウンキャスト〉って言って、ホントはしない方がいい
キャストなんです
しちゃいけない?
継承してるってことは、 CListBox は CWnd に色々新しいのを付け加えて
あるってことでしょ
そりゃ、 AddString() は CWnd にないもんね
ってことは、 CWnd を CListBox に無理矢理キャストしちゃうと、 CWnd 
の〈足りない状態〉で、 CListBox の操作をするから……
……それってかなりやばくない?
ま、このコントロール関係のクラスは、そういう問題が起きないように作
られてるみたいだから大丈夫なんだろうけど、ホントはこういうのはしない
方がいいかな
そうなんだ……でも、じゃーどうするの?
この辺は、〈クラス〉の仕組みそのものが複雑で、それを MFC が無理矢
理使ってるから問題になってるから
あ、 API でやればいいんだ!
そういうこと。でも API の方が面倒なんで、まずは API と MFC の両方
を使ってしてみましょう

// いつものメンバ関数。
void CFileTestDlg::OnBtnShow() 
{
    CButton cShowBtn;
    cShowBtn.Attach
        ( ::GetDlgItem( GetSafeHwnd(), IDC_BTN_SHOW ) );
    cShowBtn.SetWindowText( "あいうえお" );
    cShowBtn.Detach();
    return;
//  あとは取っておきましょう。

あ、 CListBox が CButton になった
いやね、今回の方法はもうクラスウィザードで変数と結び付けられちゃっ
てるコントロールには使えないんで、代わりに〈表示〉ボタンで
 m_cDataLstBox みたいになってるとダメってこと?
そういうこと。 MFC がそうなってるかどうか監視してて、なってるとエ
ラーになっちゃうんだよね
キビシー
だから、クラスウィザードで結びつけてないボタンを例にします。逆に言
うと、 m_cDataLstBox を関連させないようにしちゃえば CListBox でもで
きるから
そういうもんなのね。で、2行目の Attach() って初見。 MSDN 見ると、 
CWnd のメンバ関数だね
何度も言うけど、コントロールもウィンドウ
うん、何度も聞いた
 CWnd の中にはウィンドウハンドルを格納してるわけだけど
 CWnd::GetSafeHwnd() で取り出せるヤツね
そのウィンドウハンドルを CWnd に格納させるのが CWnd::Attach() 

前回見たとおり、ボタンを作るには CButton::Create() を呼ばなきゃい
けなかったでしょ。ってことは、 CButton の変数を作ったときには、ボタ
ンそのものは存在しないわけ
うん、あ、だから cShowBtn の中のウィンドウハンドルは空なんだ!
そゆこと。だから、そこに Attach() でコントロールのウィンドウハンド
ルを格納させるわけ
そのコントロールのウィンドウハンドルは、 API の GetDlgItem() で拾
えるんだね。これって、ホントに MFC のにウィンドウハンドル付け加えた
のだね
でしょう、 API はたいがい、最初にウィンドウハンドルとかを渡すから
で、 SetWindowText() って呼んでる
 CWnd::SetWindowText() は、ホントはウィンドウのタイトルを変えるた
めのメンバ関数。たとえば……

// いつものメンバ関数。
void CFileTestDlg::OnBtnShow() 
{
    SetWindowText( "かきくけこ" );
    return;
//  あとは取っておきましょう。

うお、ダイアログのタイトルバーが〈かきくけこ〉になった!
だけど、ボタンの場合にはボタンの名前が変わります
あ、〈あいうえお〉になってる。へー気付かなかった……なんかちょっと
複雑。あ!
そう、前回ちょっとしたでしょ
ボタンだとその文字、ウィンドウだとタイトル、ね。同じものね〜
ウィンドウズの仕様だからしょうがないんだけどね。で、最後に 
CWnd::Detach() を呼ぶんだけど、これがちょっとクセモノかな
ってゆーか、なんのために呼んでるの?
じゃ、これ呼ばないで試してみて
ほい……あ、なんかダイアログ出てエラーになった!
こっから少し複雑になるから注意してね。まず、 std::ifstream を思い
出して
いきなりだね。ファイルからデータを取り出すクラスだよね
 fopen() も思い出して
 API の、ファイルを開くのだよね
 fopen() で開いたファイルは
 fclose() で閉じなきゃいけないんだよね。でも std::ifstream の方は
なんにもしないで勝手に閉じてくれるんだよね
そう。クラスには〈デストラクタ〉って言って、変数がなくなるときに自
動的に呼ばれる関数があるんです
そんなかで fclose() してくれるんだよね
そういうこと。で、この〈デストラクタの後処理〉は、 CWnd にも付いて
ます
 CWnd はファイルと関係ないじゃん
ファイルハンドルの代わりに?
ウィンドウハンドルを持ってる……ってことは、 CWnd のデストラクタは
ウィンドウハンドルを閉じちゃう?
そう、それはすなわち〈ウィンドウを削除しちゃう〉ってこと
えええっ!? それってまずいじゃない。あ! だから CWnd::Detach() 
を呼ぶの?
そういうこと! CWnd はデストラクタで、自分が持ってるウィンドウを
削除します。でも、今回みたいに〈ずっと表示されてるウィンドウをちょっ
と操作するために CWnd に Attach() する〉場合には
削除されちゃったら困る!!
だから、削除されないように CWnd::Detach() を呼びます。このメンバ関
数は CWnd が持ってるウィンドウハンドルを NULL に置き換えてくれるから、
削除されません
自動でしてくれるのが、仇になっちゃうんだ
っていうか、このデストラクタの機能が役立つ場面ってほとんどないか
な……
質問!
はい火美ちゃん
最初の CListBox * のときは、こーゆーこと全然考えなくていーの?
そう、ポインタだからね。もしポインタがなくなるときにデストラクタが
呼ばれちゃったら、ポインタの数だけデストラクタが呼ばれちゃうでしょ?
そっか、ポインタは本体指し示してるだけなんだもんね
そういうこと。デストラクタは本体が消える時の1度だけ呼ばれればいい
から
じゃ、そのダウンキャストだっけ、それ以外は MFC 使った方がメリット
多いってことになるの?
そういうことになるね。ポインタが返ってきてそれを操作するようになっ
てるのも、こういう煩わしさから解放する意味があるのかも
あ、でも、もしかしたら全部 API でやると面倒じゃないとか?
そんなことはないんだよねー
げげ
というわけで次回に続く!

/*
    Preview Next Story!
*/
最近ちょっと難しくない?
それは言えるね。 C++ の細かいこととか教えてるし
ウィンドウズのこともねー。なんか〈仕様〉ってやな感じ
そういうのに振り回され続けるのがこの仕事……
というわけで次回
< Version 5.27 メッセージを送ろう! >
につづく!
ま、慣れちゃえば問題なし!
それはどうかと思うけど……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。