Version 9.09
ツールバーを使ってみよう!
「今回はツールバーについて見てみます」
『おー』
「ツールバーはメニューの下にある横棒。だけど……えっと、
Version 9.01 ( No.162 ) の時みたいに Spy++ を起動して、ツールバーに
照準合わせてみて」
『ほいほい。2重なんだよね』
「そう、そこがポイント。【ウィンドウクラス】って憶えてる?」
『 Version 5.23 ( No.088 ) でやったね』
「このウィンドウクラス名を見ると、ウィンドウの素性がだいたい判るんで
す」
『え、そうなの?』
「たとえば、ダイアログコントロールなんかはウィンドウズが提供してくれ
るものだから、あらかじめ全部ウィンドウクラス名が決まってます」
『ボタンが BUTTON とか?』
「そうそう、それ。 MSDN の CreateWindow() のページに書いてあるから一
通り見てみて」
『たいがいのコントロールはちゃんとあるんだね』
「もし他のアプリで〈あれ、このコントロール、動きが変〉とか思ってウィ
ンドウクラス名を調べてみたら標準のコントロールじゃなかった、っていう
ことは結構多いよ」
『そういう意味で素性が判るってわけね』
「そゆこと。というわけで、コントロールバーに照準を合わせて、
【ウィンドウ検索】ダイアログの【クラス】の所を見てみて」
『えっと、外側のが AfxControlBar42d で、内側のが ToolbarWindow32 だ
ね』
「まず、本当のツールバーは内側の ToolbarWindow32 の方」
『本当?』
「つまりこれが、ウィンドウズが用意してくれてるツールバー」
『あー、ツールバーもウィンドウズが用意してくれてるんだ』
「で、外側の AfxControlBar42d は、 MFC が作ったウィンドウ」
『これはウィンドウズのじゃないんだねー』
「そう。だから、 MFC が作ったウィンドウの上に、ウィンドウズのツール
バーが乗ってるって感じかな」
『フレームウィンドウの上にビューウィンドウが乗ってるみたい』
「それに近いかも。ちなみに Afx っていうのは MFC の印だと思って」
『あ! そういえば Afx ってよく出てきたねー』
「 MFC のマクロや関数の頭に付いてるからね。こういうとこを見れば素性
が判るってこと」
『でもそれを知らないと判らないじゃん』
「だから今憶えて」
『んー』
「さて、今ので判ったように、ツールバー自体はウィンドウズが提供してく
れてるものです」
『例によって、 MFC でも使えるし、 API だけでも使えるって事ね』
「そゆこと。ま、その辺を踏まえつつ、実際に使ってみます」
『ってゆーか、最初から表示されてるよね』
「うん。これは CMainFrame::OnCreate() の中で」
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 略。
// 注:横幅を短くするために改行しています。
if ( !m_wndToolBar.CreateEx
( this
, TBSTYLE_FLAT
, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER
| CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC
)
||
!m_wndToolBar.LoadToolBar( IDR_MAINFRAME )
)
{
TRACE0("Failed to create toolbar\n");
return -1; // 作成に失敗
}
// 略
}
「ってしてるでしょ。ここでツールバーを作ってます」
『確かに CreateEx() ってなんか作ってる感じ……だけどちょっと複雑ね』
「これは悪いプログラムの書き方かも。まず if を取ると」
!m_wndToolBar.CreateEx
( this
, TBSTYLE_FLAT
, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER
| CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC
)
||
!m_wndToolBar.LoadToolBar( IDR_MAINFRAME )
『んーと、小カッコがこうだから……』
!m_wndToolBar.CreateEx
( this
, TBSTYLE_FLAT
, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER
| CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC
)
『と』
!m_wndToolBar.LoadToolBar( IDR_MAINFRAME )
『に分かれてるんだよね』
「そう、それを || で継ないでるだけ」
『 || って、どっちかが 0 以外なら 0 以外になるんだよね』
「そうそう。 Version 6.10 ( No.110 ) を参照ってことで、でもここでは
! が付いてるから」
『な、なんか複雑……』
「まず最初の m_wndToolBar.CreateEx() を呼んでるところから」
『 m_ ってことはメンバ変数なんだね』
「そう、 m_wndToolBar は CMainFrame のメンバ変数。 MainFrame.h の方
を見れば分かるからあとで見ておいて」
『はーい』
「この m_wndToolBar は CToolBar 型」
『まさにツールバーって感じね』
「で、 CToolBar::CreateEx() でツールバーを作ります。それが最初の部
分」
『 this って……なんだっけ、自分自身のポインタとかなんとかなんだよ
ね』
「やっぱ this って難しいかもね……今呼ばれてる
CMainFrame::OnCreate() ってメンバ関数も、どこかで
m_wndToolBar.CreateEx() みたいな感じに呼ばれてるはず」
『はずよね』
「その m_wndToolBar にあたる変数があるわけでしょ。そのポインタ」
『……まだよく分かんない』
「だね……これは後でちゃーんと説明するから、それまでは。あ!」
『な、なに?』
「んー、ちょっと間違った説明の仕方かもしれないけど、
CToolBar::CreateEx() の第1引数にはツールバーを置くウィンドウのポイ
ンタを渡す必要があるんです」
『ツールバーを置くウィンドウ、つまりフレームウィンドウ……あー、って
ことは CMainFrame のポインタを渡すわけだから』
「だから this 」
『だまされてる気がする……』
「うん、ちょっと間違ってる部分もあるし、今のところはそのくらいって事
で」
『えっと、2番目の引数は、なんかのフラグみたいだけど』
「これはツールバーのスタイルを決めるフラグ」
『あれ? でも3番目の引数もそんな感じっぽいけど』
「うん、こっちもスタイル。ものすごく分かりにくいんだけど……第2引数
のは本当のツールバーにだけ渡したいスタイル、第3引数はツールバー全体
にも渡したいスタイル、ってところかな」
『……なんかよくわかんないね』
「僕も分からない」
『何それ』
「一応関数の中を見ればそうらしいっていうのは分かるんだけどね。 MSDN
の方には詳しく書かれてないし。ま、この辺はパスってことで」
『テキトーねー』
「で、次に」
!m_wndToolBar.LoadToolBar( IDR_MAINFRAME )
「を呼んでます。この CToolBar::LoadToolBar() を呼ぶと、ツールバーを
実際に作ります」
『へ? さっき作ったんじゃないの?』
「さっきはウィンドウとしてのツールバーだけ。ここでは、リソースの
IDR_MAINFRAME からツールバーのボタンひとつひとつを読み込んで追加して
いるんです」
『あら、面倒そう』
「確かに。で、このふたつでツールバーは完成。めでたく表示されるという
わけです」
『あ、ちょっと試していい?』
「どうぞ」
『この部分をコメントアウトすると……げ! エラーになっちゃった』
「 ASSERT() しちゃったね。これは、下の方に」
// TODO: ツール バーをドッキング可能にしない場合は以下の3行を
// 削除してください。
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
「ってあるでしょ、こっちもコメントアウトしないとダメだから」
『あ、こっちもしたら大丈夫だね。うん、ツールバーないし』
「この部分でツールバーを実際にウィンドウにくっつけてるんです。で、
その時にツールバーが作られてないと」
『くっつけるものがないんだ』
「そゆこと。あ、ちなみに ASSERT() って憶えてる?」
『 Version 6.17 ( No.117 ) でやったね。あっちゃいけないのを網に掛け
るってゆーの。そっか! ここだと、ツールバーが作られてないのにウィン
ドウにくっつけようとしたから!』
「そゆこと。つまりこの ASSERT() は〈まずツールバーを作って、そのあと
ウィンドウにくっつける〉っていう手順を守らせるためのものってこと」
『……でも今の ASSERT() だけでそれってわかるもん?』
「うーん、ちょっと難しいかもね……」
『あ、あとひとつ質問! さっきの if の ! とか || とかっていまいち分
かんないんだけど』
「そうだねそれはちゃんとやっておこうか。さっきのをはしょって書くと」
if (
!m_wndToolBar.CreateEx()
||
!m_wndToolBar.LoadToolBar()
)
『だいぶはしょったね……』
「で、この if の中をひとつひとつ見ていきます。 CToolBar::CreateEx()
は、作れたら 0 以外、作れなかったら 0 を返します」
『それが ! で逆になるんだから、 作れたら 0 、作れなかったら 0 以外
ね』
「で、次の CToolBar::LoadToolBar() も、うまくいったら 0 以外、ダメ
だったら 0 」
『これも逆になるから、うまくいったら 0 、ダメだったら 0 以外ね』
「 || は〈どっちかが 0 以外なら 0 以外、両方とも 0 の時だけ 0 〉だか
ら」
『えっと……あ、両方うまくいった時だけ 0 になるんだね』
「言い換えるとどっちかがダメだったら 0 以外。で、 if の中に入って
return しちゃうから、ダイアログは作られません」
『ほー。つまりツールバーがちゃんと作られてるかどうか調べてるのね』
「でも実は CToolBar::CreateEx() がエラーだと CToolBar::LoadToolBar()
は呼ばれないんだけどね」
『え? なんで??』
「というわけで次回に続く!」
/*
Preview Next Story!
*/
『なんかここ最近、いろんな話が出てくるね』
「そうだね、文法的なこととかウィンドウズのこととか」
『まとめて教えた方がいくない?』
「火美ちゃんは API かたっぱしから教わりたい?」
『それなんかヤダ』
「というわけで次回」
< Version 9.10 ショートサーキット >
『につづく!』
「飽きないためにもいろんなことを少しずつ、ってことで」
『にしても話が飛びすぎのよーな……』