32章 メニューとキーボードアクセラレーター(その4)

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis"></meta>
<title>32章 メニューとキーボードアクセラレーター(その4)
</title>
</head>

<body bgcolor="WHITE">
<font size="5">32章 メニューとキーボードアクセラレーター(その4)
</font>
<hr>
<p>
<center>
<a href="chap32.lzh">ダウンロード</a>
</center>
<p>
 今回は、29章のキーボードによる操作(その2)(キーボードアクセラレータの実装)について説明します。一からサンプルを作成するのではなく、6章で用いたサンプルのメニューをキーボードだけで操作できるように拡張する形で行います。6章をお読みになっていない方は、6章を読んでから、この章を読むようにしてください。
<hr>
<p>
<b>・リソースエディタでキーボードアクセラレーターテーブルを作る</b>
<p>
 キーボードアクセラレーターもリソースですので、リソースエディタで作成します。以下、作成画面で説明します。
<p>
<center>
<b>図32-1</b>
</center>
<p>
 図32-1は、リソースを作成するときのおなじみの画面ですね。キーボードアクセラレータテーブルもここから作成します。
<p>
<center>
<b>図32-2</b>
</center>
<p>
 図32-2は、これもおなじみの画面。今までは、Menuを選択していましたが、今回はAcceleratorを選択します。
<p>
<center>
<b>図32-3</b>
</center>
<p>
 すると、図32-3の画面になります。リストビューの青いバーの箇所をマウスで左クリックすると、図32-4の画面になります。
<p>
<center>
<b>図32-4</b>
</center>
<p>
 図32-4の画面では、<b><i><u>ID項目のコンボボックスで、メニューで使ったID項目を選択するのが重要です。</u></i></b>[キータイピング登録]ボタンを押すと、ショートカットとなるキーを選択するように尋ねてきます。[F2]キーを押すと、図32-5の様になります。ここで[Enter]キーを押すと、次の項目の入力が出来ます。
<p>
<center>
<b>図32-5</b>
</center>
<p>
 同様にF3キーにもメニュー項目のIDを割り当てます。すると図32-6になります。
<p>
<center>
<b>図32-6</b>
</center>
<p>
<center>
<b>図32-7</b>
</center>
<p>
 そして、メニュー項目のキャプションも変更する必要があります。これでないと、オペレーターは、どのメニュー項目にショートカットキーが割り当てられているか分からないからです。図32-7は、キャプション中の半角の¥tは、単なるタブです。C言語ではおなじみですね。
<hr>
<p>
<b>・アクセラレーターテーブルの使い方</b>
<p>
 さて、これで、アクセラレーターの準備が出来ました。あとは、ソースコードの追加変更です。<br>
 重要な相違点は、<b><i><u>アクセラレーターテーブルの読み込み</u></i></b>と<b><i><u>メッセージループの変更</u></i></b>です。
<p>
<table border="1" bgcolor="#F0F0F0">
<caption align="BOTTOM">リスト32-1
<tr><td>
<pre>
/* C言語で始めるWindowsプログラミング */
/* 32章のサンプルプログラム */
/* Programmed by Y.Kondo */
/* 注:TABサイズは4で見てください */
/* このファイルではWinMain関数が定義して*/
/*ある */

#define STRICT
#include &lt;windows.h&gt;
#include "wndproc.h"
#include "resource.h"

/* アプリケーションエントリーポイント */
int WINAPI WinMain(HINSTANCE hInstance,
                 HINSTANCE    hPrevInstance,
                  LPSTR        CmdLine,
                  int          CmdShow)
{
  HWND            hwnd;   /*  メインウインドウのウインドウハンドル    */
   MSG             msg;    /*  メッセージキューから取得したメッセージ  */
   WNDCLASS        wc;     /*  ウインドウクラス登録用の構造体          */
   <b>HACCEL          Ac;     /*  アクセラレーターへのハンドル            */</b>

  wc.style        =0;
   wc.lpfnWndProc  =WindowProc;
   wc.cbClsExtra   =0;
   wc.cbWndExtra   =0;
   wc.hInstance    =hInstance;
   wc.hIcon        =LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
   wc.hCursor      =LoadCursor(NULL,IDC_ARROW);
   wc.hbrBackground=GetStockObject(LTGRAY_BRUSH);  /*  背景のブラシは灰色          */
   wc.lpszMenuName =MAKEINTRESOURCE(IDR_MENU1);    /*  クラスにメニューを付ける    */
   wc.lpszClassName="MainWindowClass";
   
   if(RegisterClass(&wc;)==0)               /*  ウインドウクラス登録    */
       return  0;

  hwnd=CreateWindow(  "MainWindowClass",  /*  ウインドウ作成          */  
                       "32章サンプル",
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       NULL,
                       (HMENU)NULL,
                       hInstance,
                       0);
   if(hwnd==NULL)
       return  0;

  ShowWindow(hwnd,CmdShow);           /*  ウインドウの表示        */
   UpdateWindow(hwnd);                 /*  ウインドウの最初の更新  */

  /*  ここでリソースとしてのキーボードアクセラレーターテーブルを読み込んでいる*/
   <b>Ac=LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1));

  while(GetMessage(&msg;,NULL,0,0))    /*  メッセージループ        */
   {
       if(!TranslateAccelerator(hwnd,Ac,&msg;))
       {
           TranslateMessage(&msg;);
           DispatchMessage(&msg;);
       }
   }</b>
   return  msg.wParam;
}
</pre>
</table>
<p>
・<b><u><i>LoadAccelerators関数</i></u></b><br>
 第一引数は、インスタンスハンドル。第二引数は、アクセラレーターテーブルの名前ですが、リソースエディタは定数を生成しますので、MAKEINTSESOURCEマクロで変換した物を引数とする必要があります。<br>
 成功した場合、キーボードアクセラレータテーブルのハンドルを返し、失敗した場合は、NULLを返します。
<p>
・<b><u><i>TranslateAccelerator関数</i></u></b><br>
 第一引数は、関連付けるウインドウハンドル。第二引数は、キーボードアクセラレーターテーブルへのハンドル。第三引数は、GetMessage関数が吸い上げたMSG構造体変数へのポインタ。<br>
 機能は、WM_KEYDOWNメッセージやWM_SYSKEYDOWNメッセージを受け取り、キーボードアクセラレーターテーブルに該当する物が見つかれば、WM_COMMANDメッセージやWM_SYSCOMMANDメッセージに変換し、ウインドウプロシージャにSENDします。<br>
 成功した場合は、TRUEを返し、失敗した場合は、FALSEを返します。<br>
 これゆえ、キーボードアクセラレータを使う場合は、今回の様なメッセージループになります。
<p>
 重要な事ですが、TranslateAccelerator関数の引数を見て分かるように、キーボードアクセラレーターとメニューは、特に、関係していません。メニューに存在しないショートカットキーがあっても良いという事です。しかし、メニューと同義なショートカットキーが定義されていた場合、メニューが使用不可の場合は、動作しません。

<hr>
<p>
<b>・メニューの初期化の機会</b>
<p>
 さて、今回のサンプルは、6章のサンプルと比べて、メニューの概観に大きな特徴があります。つまり、四角形が表示されているときは、三角形しか選べない。逆も真なりです。<br>
 この様に、メニューを表示するとき、アプリケーションの状態で、メニューの属性を変える事は度々あります。今回のサンプルでは、新たなメッセージを紹介し、どのように行うのかを説明します。<br>
 まずは、ソースコードを提示します。
<p>
<table border="1" bgcolor="#F0F0F0">
<caption align="BOTTOM">リスト32-2
<tr><td>
<pre>
/* C言語で始めるWindowsプログラミング */
/* 32章のサンプルプログラム */
/* Programmed by Y.Kondo */
/* 注:TABサイズは4で見てください */
/* このファイルでは、メインウインドウのウインド*/
/*ウプロシージャが定義されている */

#define STRICT
#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include "wndproc.h"
#include "resource.h"

/*===============================================================================*/

/* このファイル内でのみ用いられる関数のプロトタイプ宣言 */
static LRESULT Wm_InitmenuProc(HWND,HMENU);
static LRESULT Wm_CommandProc(HWND,WORD,WORD,HWND);
static LRESULT Wm_DestroyProc(void);
static LRESULT Wm_PaintProc(HWND);

/* メインウインドウのウインドウプロシージャ */
LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
  switch(message)
   {
       <b>case    WM_INITMENU:        /*  今回、新しく出てきたメッセージ  */</b>
           return  Wm_InitmenuProc(hwnd,(HMENU)wparam);
       case    WM_COMMAND:         /*  メニューに対する処理    */
           return  Wm_CommandProc(hwnd,HIWORD(wparam),LOWORD(wparam),(HWND)lparam);
       case    WM_PAINT:           /*  再描画処理              */
           return  Wm_PaintProc(hwnd);
       case    WM_DESTROY:         /*  ウインドウの破壊後処理  */
           return  Wm_DestroyProc();
   }
   return  DefWindowProc(hwnd,message,wparam,lparam);
}

/*===============================================================================*/

/* このファイル内でのみ用いられる型定義 */
typedef enum
{
  RECTANGLE,
   TRIANGLE
} TState;

/* 図形の状態 */
static TState StateFlag=RECTANGLE;

<b>
static LRESULT Wm_InitmenuProc(HWND hwnd,HMENU hMenu)
{
  if(StateFlag==RECTANGLE)
   {
       EnableMenuItem(hMenu,ID_TRIANGLE,MF_BYCOMMAND|MF_ENABLED);
       EnableMenuItem(hMenu,ID_RECTANGLE,MF_BYCOMMAND|MF_GRAYED);
   }
   else
   {
       EnableMenuItem(hMenu,ID_TRIANGLE,MF_BYCOMMAND|MF_GRAYED);
       EnableMenuItem(hMenu,ID_RECTANGLE,MF_BYCOMMAND|MF_ENABLED);
   }
   return  0;
}
</b>
static LRESULT Wm_CommandProc(HWND hwnd,WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
  switch(wID)
   {
       case    ID_RECTANGLE:
           StateFlag=RECTANGLE;
           InvalidateRect(hwnd,NULL,TRUE);
           UpdateWindow(hwnd);
           break;
       case    ID_TRIANGLE:
           StateFlag=TRIANGLE;
           InvalidateRect(hwnd,NULL,TRUE);
           UpdateWindow(hwnd);
           break;
   }
   return  0;
}
static LRESULT Wm_DestroyProc(void)
{
  PostQuitMessage(0);
   return  0;
}

static LRESULT Wm_PaintProc(HWND hwnd)
{
  PAINTSTRUCT ps;
   HDC         PaintDC;
   /*  四角形のデータ  */
   POINT   RA[]={{10,10},{190,10},{190,190},{10,190},{10,10}};
   /*  三角形のデータ  */
   POINT   TA[]={{100,10},{190,190},{10,190},{100,10}};

  if(GetUpdateRect(hwnd,NULL,TRUE))
   {
       PaintDC=BeginPaint(hwnd,&ps;);
       if(StateFlag==RECTANGLE)
           Polyline(PaintDC,RA,sizeof(RA)/sizeof(POINT));
       else
           Polyline(PaintDC,TA,sizeof(TA)/sizeof(POINT));
       EndPaint(hwnd,&ps;);
   }
   return  0;
}
</pre>
</table>
<p>
・<b><u><i>WM_INITMENUメッセージ</i></u></b><br>
 このメッセージは、メニューがアクティブになる直前に、ウインドウプロシージャに送られてきます。このメッセージを利用して、アプリケーションの状態に応じて、メニュー項目を活性化したり不活性化したりする事が出来ます。
<p>
 今回のサンプルでは、状態に応じて、メニュー項目の活性化や不活性化を行っています。具体的には、EnableMenuItem関数を用いています。この様な、メニューを操作する関数は、次回にまとめて説明しますので、今回は、特に説明しません。
<hr>
<p>
 今回は、結構、盛りだくさんでした。ちょっと、読むのに疲れたかも知れませんね。<br>
 次回は、メニューを活性化させたり、チェックを入れたりする関数群の紹介をします。
<p>
 では、お楽しみに。
<p align="RIGHT">
2002年12月09日<br>
<hr>
<p align="RIGHT">
<a href="/web/20130706105410/http://web.kyoto-inet.or.jp/people/ysskondo/index.html">目次</a><br>
<hr>
<p align="RIGHT">
著作権者:近藤妥
</body>
</html>

  • 最終更新:2018-03-11 05:27:42

このWIKIを編集するにはパスワード入力が必要です

認証パスワード