#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のトップページをご覧ください。