Version 9.08
今度こそアクセラレーターを追加する!
「前回のアクセラレーターを新しく作るコード」
void CMainFrame::OnMenuTest()
{
// アクセラレーターテーブルを新しく作ります。
ACCEL stAccel;
stAccel.fVirt = FCONTROL | FVIRTKEY;
stAccel.cmd = ID_FILE_OPEN;
stAccel.key = 'B';
HACCEL hAccel
= CreateAcceleratorTable( &stAccel, 1 );
// 古いアクセラレーターテーブルを削除します。
DestroyAcceleratorTable( m_hAccelTable );
// アクセラレーターテーブルへのハンドルを入れ替えます。
m_hAccelTable = hAccel;
}
『ってゆーかこれってダメじゃん! 新しく Ctrl + B ができるようになっ
たと思ったら、 Ctrl + O とか全部なくなっちゃったし』
「そう、そこが問題。この方法は」
1: Ctrl + B だけしかないアクセラレーターテーブルを作る。
2:古いアクセラレーターテーブル( Ctrl + O 含む)を削除する。
3:新しいアクセラレーターテーブルをセットする
「って方法を取ってます」
『それじゃ Ctrl + O とかが使えなくなっちゃうわけね。でもさ、他のリ
ソースとかなら Insert なんたらとかでできたのに』
「アクセラレーターテーブルはそういうのがないから、今あるものにそのま
ま追加することはできないんです。だから」
1:古いアクセラレーターテーブルの複製を作る。
2:複製に Ctrl + B のアクセラレーターを追加する。
3:古いアクセラレーターテーブルを削除する。
4:複製をセットする。
『つまり、一度手元に持ってきて追加してからセットするわけね』
「そゆこと。で、この中で一番難しいのは、複製を作ったり追加するとこ
ろ」
『見た感じ難しそうには見えないけど』
「この部分も含めてもう少し詳しく書くと」
1:古いアクセラレーターテーブルのアクセラレーターの数を取得する。
2:その数+1分のアクセラレーターの変数を用意する。
3:その変数に古いアクセラレーターテーブルの情報をコピーする。
4:余った1個分に Ctrl + B のアクセラレーターの情報を置く。
5:その変数でアクセラレーターテーブルを新しく作成する。
6:古いアクセラレーターテーブルを削除する。
7:新しく作ったアクセラレーターテーブルをセットする。
『難しいような、難しくないような……最初の数を取得って、前回やった
し』
「そういう所もあるし、ところどころ前にやってるのもあるけどね。だから
ひとつひとつ手順を追っていけば大丈夫……だと思う」
『不安ねー』
「がんばるのは火美ちゃん」
『水希ちゃんもがんばるよーに』
「はいはい。じゃ、コードを見てみましょう」
void CMainFrame::OnMenuTest()
{
// アイテム数を取得します。
int iTableNum
= CopyAcceleratorTable( m_hAccelTable, NULL, 0 );
// アイテム数 + 1 分の ACCEL 構造体配列を確保します。
ACCEL *pstAccel = new ACCEL[iTableNum + 1];
// 古いアクセラレーターテーブルをコピーします。
CopyAcceleratorTable
( m_hAccelTable
, pstAccel
, iTableNum
);
// + 1 の所に新しいアクセラレーターのデータを入れます。
pstAccel[iTableNum].fVirt = FCONTROL | FVIRTKEY;
pstAccel[iTableNum].cmd = ID_FILE_OPEN;
pstAccel[iTableNum].key = 'B';
// アクセラレーターテーブルを新規作成します。
HACCEL hNewAccel
= CreateAcceleratorTable( pstAccel, iTableNum + 1 );
// 確保した配列を削除します。
delete [] pstAccel;
// 古いアクセラレーターテーブルを削除します。
DestroyAcceleratorTable( m_hAccelTable );
// アクセラレーターテーブルへのハンドルを入れ替えます。
m_hAccelTable = hNewAccel;
}
『なが!』
「というわけで、ひとつひとつ見ていきます」
『まず CopyAcceleratorTable() は、前回やったからいーとして。次の』
// アイテム数 + 1 分の ACCEL 構造体配列を確保します。
ACCEL *pstAccel = new ACCEL[iTableNum + 1];
『これが謎』
「 new は一応使ったことあるんだけどね」
『え? 検索……あ、 Version 5.22 ( No.087 ) でやってたね』
「 new は、変数をつくるためのキーワード。えっと、このあとで今アプリ
が持っているアクセラレーターテーブルのデータを取ってきて受け取る必要
があります」
『さっきの〈3:その変数に古いアクセラレーターテーブルの情報をコピー
する。〉のことね。ってことはその前の〈2:その数+1分のアクセラレー
ターの変数を用意する。〉がこの行なんだ』
「そゆこと。前回アクセラレーターテーブルを作ったときに ACCEL 構造体
を使ったでしょ」
『うん使った。あの中にどういうキーの時にどういうコマンドが送られる
かって入れたんだよね。そっか、この変数でそういう情報を受け取るんだ』
「そゆこと。その情報を受け取るために、最初にアクセラレーターがいくつ
入ってるか調べて、」
new ACCEL[iTableNum + 1];
「でその数 + 1 個分の ACCEL 構造体を作って、それをポインタとして受け
取ってるんです。イメージとしては、 iTableNum が 3 なら、 + 1 で4個
だから」
[ACCEL][ACCEL][ACCEL][ACCEL]
「って感じにメモリ上に ACCEL 構造体が4つできることになります」
『返ってくるポインタって、一番最初の ACCEL のアドレスなんだよね。
あ、そういえばなんで + 1 ?』
「だって、今回の例ではアクセラレーターを追加しなきゃいけないから」
『だから1個増やしてるんだ』
「で、変数を用意したら、そこにコピーします」
// 古いアクセラレーターテーブルをコピーします。
CopyAcceleratorTable
( m_hAccelTable
, pstAccel
, iTableNum
);
『 m_hAccelTable は前回やった、今持ってるアクセラレーターテーブルの
ハンドルね。そっから、第2引数の……?』
「ポインタだよ。 new で作ったのを受け取る時はポインタだから」
『さっきのページにそう書いてあるね』
「そのポインタを渡すと、 CopyAcceleratorTable() がそのポインタを通し
て実際に new で作られた変数に情報を書き込んでくれます」
『むむむ』
「このコピーの部分は文字列のとかと同じだよ?」
『う……文字列のときはもう慣れでやっちゃってるからイメージ掴めない
よー』
「かもね。そういうときは Version 5.03 ( No.068 ) 以降を読み返して」
『はーい』
「で、第3引数に iTableNum 、つまり今持ってるアクセラレーターの数を
渡すと、その数だけ pstAccel にコピーしてくれます」
『あ、そういえばこの CopyAcceleratorTable() って、アクセラレーターの
数をもらったときのと同じ API だね』
「そう、だからこの API にはふたつの機能が入ってるってことだね。本当
はこういうのは良くないんだけど……」
『で、次の』
// + 1 の所に新しいアクセラレーターのデータを入れます。
pstAccel[iTableNum].fVirt = FCONTROL | FVIRTKEY;
pstAccel[iTableNum].cmd = ID_FILE_OPEN;
pstAccel[iTableNum].key = 'B';
『これって、前回のと同じ……だけどちょっと違うね』
「さっきのコピーでは iTableNum 分しかコピーしてないから、さっきのイ
メージだと」
[コピー済み][コピー済み][コピー済み][何も入ってない]
「って感じになってます。で、この部分で最後の1個に追加するデータを入
れてるわけ」
『なら』
pstAccel[iTableNum + 1].fVirt = FCONTROL | FVIRTKEY;
『じゃないの?』
「だって、配列は 0 から始まるから」
『あ、そっか。さっきのだと』
[0][1][2][3]
『で、 iTableNum が 3 だから合ってるんだ』
「まぁ、配列の最後の要素は、要素の数 - 1 。今回配列の要素の数は
iTableNum + 1 。だから ( iTableNum + 1 ) - 1 って書く手もあるよ」
『それって変……』
「僕は前やってたよ。分かりやすいから」
『……なんか恥ずかしくない?』
「分かりやすさの方が大事だと思うから。で、」
// アクセラレーターテーブルを新規作成します。
HACCEL hNewAccel
= CreateAcceleratorTable( pstAccel, iTableNum + 1 );
『これは前回のだね。あ、でも第2引数が違う』
「前回はアクセラレーターがひとつだけだったけど」
『今回は元々あったのも入ってるからいっぱいなんだね』
「で、そのあと」
// 確保した配列を削除します。
delete [] pstAccel;
『これって new した変数を消すのなんだよね』
「そうそう。普通の変数は関数が終わるときに自動的に消えるんだけど、
new したのは delete で消さないとアプリが終了するまで消えないから」
『でもさ、これって削除しちゃまずいんじゃない? だって、これからアク
セラレーターテーブル使うんでしょ?』
「大丈夫大丈夫。さっき CreateAcceleratorTable() で、ウィンドウズシス
テムの中に本当のアクセラレーターテーブルを作ってもらったんだから」
『本当の?』
「そう。 pstAccel は、そのアクセラレーターテーブルを作るためのただの
情報。たとえば、 Version 9.04 ( No.165 ) でメニューアイテムを追加し
たとき、 CMenu::InsertMenu() に渡した情報とかは」
『そっか、もうなくなってるけど、メニューアイテムはちゃんと作られてる
ね』
「それと同じ。あとの行は前回と同じだから大丈夫だよね」
『うん、なんとか』
/*
Preview Next Story!
*/
『今日一番難しかったのって配列のとこかも』
「うん、そこが一番難しいと思うよ」
『そなの?』
「やっぱりメモリイメージとかは解りにくいからね。でも直接見れば」
『あ、メモリ見ればいいんだね』
「面倒だけど、それもひとつの手ってことで」
『いうわけで次回』
< Version 9.09 ツールバーを使ってみよう! >
「につづく!」
『今度は解りやすそうね』
「ところがどっこい」
『げ!』