#pragma twice

KAB-studio > プログラミング > #pragma twice > 169 Version 9.08 今度こそアクセラレーターを追加する!

#pragma twice 169 Version 9.08 今度こそアクセラレーターを追加する!

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

 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 ツールバーを使ってみよう! >
「につづく!」
『今度は解りやすそうね』
「ところがどっこい」
『げ!』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。