理論は後からついてくる?!

12/10/1999 by Shigeyuki Seko


応用編

8) メニューによる音の ON/OFF

音が付いたのはいいのですが、常に音が出ているのも不便です。音を消したいと思う場面もあります。
そこで、メニューから自由に音の ON/OFF ができるようにしましょう。これはリソースとCのソースの両方を修正します。
まず、リソースファイル book.rcp を開きます。このリソースの下の方にメニューに関する記述があります。

MENU ID 3600
BEGIN
  PULLDOWN "Menu"
  BEGIN
    MENUITEM "About" 3601
  END
  PULLDOWN "Page"
  BEGIN
    MENUITEM "Go Start Page" 3602
    MENUITEM SEPARATOR
    MENUITEM "Back" 3603
    MENUITEM "Next" 3604
  END
END

この MENU ID 3600 から BIGIN そして END までがメニューに関するリソースです。
PULLDOWN に続いて書かれているのがプルダウンメニューのタイトル、その下の BEGIN から END までの間に書かれた MENUITEM がプルダウンメニューです。MENUITEM の横に書かれているラベルが実際に表示されるプルダウンメニュー名でその横の数字が、このプルダウンメニューが選ばれた時にメインプログラムに渡される ID 番号です。
さて、まずは音の ON/OFF のメニューを作らなければいけません。
でも心配する事はありません。新しいプルダウンメニューを追加するのは簡単です。
以下のような新しいプルダウンメニューを作ります。

  PULLDOWN "Sound"
  BEGIN
    MENUITEM "Sound ON" 3605
    MENUITEM "Sound OFF" 3606
  END

ここで MENUITEM の ID 番号、3605,3606 は他と重複しない番号を使用してください。
この作成した新しいプルダウンメニューを実際にメニューのリソースに書き込みます。

MENU ID 3600
BEGIN
  PULLDOWN "Menu"
  BEGIN
    MENUITEM "About" 3601
  END
  PULLDOWN "Page"
  BEGIN
    MENUITEM "Go Start Page" 3602
    MENUITEM SEPARATOR
    MENUITEM "Back" 3603
    MENUITEM "Next" 3604
  END
  PULLDOWN "Sound"
  BEGIN
    MENUITEM "Sound ON" 3605
    MENUITEM "Sound OFF" 3606
  END
END

リソースの変更はこれだけです。


次に C のソースプログラムを変更します。

以下に book.c の冒頭の部分を示します。

 

/******************************
  Picture Book program
  TAB = 4
  Shigeyuki Seko
  12/6/1999
******************************/

#include  <Pilot.h>
#define  MaxPage 10

Int Page;

static void drawBitmap(Int x, Int y, Int id)
{
  VoidHand h;
  VoidPtr p;
  h = DmGet1Resource('Tbmp', id);
  if(h != NULL){
    p = MemHandleLock(h);
    WinDrawBitmap((BitmapPtr)p, x, y);
    MemHandleUnlock(h);
    DmReleaseResource(h);
  }
}

/********************************
Start
********************************/

static void StartApplication(void)
{
  FormPtr  frm;
  FieldPtr   opPtr;
  frm = FrmInitForm(1000);
  FrmSetActiveForm(frm);
  FrmDrawForm(frm);
  drawBitmap(5, 20, 7000);
  Page=0;
}

 

まず、#define MaxPage 10 のすぐ下に

#define ON 1
#define OFF 0

を記述します。この #define は便利です。これの意味はプログラム中に ON が出てきたら数字の1に、OFF が出てきたら数字の 0 に置き換えをします。define をうまく使う事で見やすいプログラムを書く事ができます。
次に音を鳴らすか鳴らさないかの情報を持った変数をひとつ定義します。
Int Page; のすぐ下に

Int SoundSW;

を記述します。この時に気を付けなければいけないのは define には ; が付きませんが Int SoundSW の最後には ; が付きますので間違えないように注意してください。

つぎに StartApplocation の修正です。この StartApplocation はプログラムがスタートする時に一回だけ実行されます。従って、変数の初期化が必要な場合にはこの関数の中で実行します。
SoundSW も初期化が必要です。最初にプログラムを立ち上げた状態(デフォルト)では、Sound は ON になっているとすると

SoundSW=ON;

と記述します。ここで最初に定義した #define が活用されます。状態が一目で理解できます。この SoundSW=ON; は StartApplocation の Page=0; の後ろに入れるといいでしょう。
ここまでの変更をした Cのソースを以下に示します。

 

/******************************
  Picture Book program
  TAB = 4
  Shigeyuki Seko
  12/6/1999
******************************/

#include  <Pilot.h>
#define  MaxPage 10
#define ON 1
#define OFF 0

Int Page;
Int SoundSW;

static void drawBitmap(Int x, Int y, Int id)
{
  VoidHand h;
  VoidPtr p;
  h = DmGet1Resource('Tbmp', id);
  if(h != NULL){
    p = MemHandleLock(h);
    WinDrawBitmap((BitmapPtr)p, x, y);
    MemHandleUnlock(h);
    DmReleaseResource(h);
  }
}

/********************************
Start
********************************/

static void StartApplication(void)
{
  FormPtr  frm;
  FieldPtr   opPtr;
  frm = FrmInitForm(1000);
  FrmSetActiveForm(frm);
  FrmDrawForm(frm);
  drawBitmap(5, 20, 7000);
  Page=0;
  SoundSW=ON;
}

さて、次に実際の SoundSW の状態に応じて音を出したり止めたりする部分を作ります。
前章で作成した SndOutput の関数を変更します。

void SndOutput (long freq,int time,int Laud)
{

SndCommandType s;
s.cmd = sndCmdFreqDurationAmp;
s.param1 = freq; /* freq (Hz) */
s.param2 = time; /* time (ms) */
s.param3 = Laud; /* Laud */
SndDoCmd(0,&s,true);

}

実際に音を出しているのは SndDoCmd(0,&s,true); ですので、SoundSW が ON の場合のみこの関数を実行するように小細工すればいい事が解ります。実際には if 文を使用します。if 文は与えられた条件が正しい場合のみ後に続く関数を実行する命令です。

void SndOutput (long freq,int time,int Laud)
{

SndCommandType s;
s.cmd = sndCmdFreqDurationAmp;
s.param1 = freq; /* freq (Hz) */
s.param2 = time; /* time (ms) */
s.param3 = Laud; /* Laud */
if (SoundSW==ON) SndDoCmd(0,&s,true);

}

これで OK です。SoundSW が ON の場合のみ SndDoCmd を実行します。
ここで、SoundSW==ON と=が2つ書かれていますが、これは代入の = と比較の = を明確に区別するためのルールです。

さて、最後にメニューに関するプログラムです。(もうひと息、がんばって!

メニューは前章で説明したハードウェアーキーと同じ MainFormHandleEvent で記述されます。
以下に示すリストの太字の部分です。

 

/********************************
Event Loop
********************************/

static Boolean MainFormHandleEvent(EventPtr event)
{
  Boolean  handled = false;
  Err    error;
  FormPtr  frm;

  if(event->eType == ctlSelectEvent){
    if(event->data.ctlEnter.controlID == 5000){  /* Go Start Page */
      Page=1;
      drawBitmap(14, 25, 7000+Page);
    }
    else if(event->data.ctlEnter.controlID == 5001){ /* Back */
      PageDown();
    }
    else if(event->data.ctlEnter.controlID == 5002){ /* Next */
      PageUp();
    }
  }
  else if(event->eType == keyDownEvent){
    if (event->data.keyDown.chr == pageUpChr){ /* Scroll up key presed */
      PageUp();
      handled = true;
    }
    else if (event->data.keyDown.chr == pageDownChr){ /* Scroll down key presed */
      PageDown();
      handled = true;
    }
  }
  else if (event->eType == menuEvent){ /* Menu event */
    switch (event->data.menu.itemID){
     case 3601: /* about */
      frm = FrmInitForm(3000);
      FrmDoDialog(frm);
      FrmDeleteForm(frm);
      break;
     case 3602:    /* Go Start Page */
      Page=1;
      drawBitmap(14, 25, 7000+Page);
      break;
     case 3603:    /* Back */
      PageDown();
      break;
     case 3604:    /* Next */
      PageUp();
      break;
    }
    handled = true;
  }
  else if(event->eType == nilEvent){
    handled = true;
  }
  return handled;
}

ここに、新しい Sound に関するメニューを追加します。
case 3602, case 3603, case 3604 はそれぞれプルダウンメニューのMENUITEM の ID 番号です。
この ID 番号はリソースファイルの中でメニューの項目で定義した ID 番号を使用します。
今回 Sound ON には 3605, Sound OFF には 3606 の ID 番号を設定しましたので以下のようになります。

     case 3605:    /* Sound ON */
      SoundSW=ON;
      break;
     case 3606:    /* Sound OFF */
      SoundSW=OFF;
      break;

従って、実際の C プログラムのMainFormHandleEventの部分は以下のようになります。

/********************************
Event Loop
********************************/

static Boolean MainFormHandleEvent(EventPtr event)
{
  Boolean  handled = false;
  Err    error;
  FormPtr  frm;

  if(event->eType == ctlSelectEvent){
    if(event->data.ctlEnter.controlID == 5000){  /* Go Start Page */
      Page=1;
      drawBitmap(14, 25, 7000+Page);
    }
    else if(event->data.ctlEnter.controlID == 5001){ /* Back */
      PageDown();
    }
    else if(event->data.ctlEnter.controlID == 5002){ /* Next */
      PageUp();
    }
  }
  else if(event->eType == keyDownEvent){
    if (event->data.keyDown.chr == pageUpChr){ /* Scroll up key presed */
      PageUp();
      handled = true;
    }
    else if (event->data.keyDown.chr == pageDownChr){ /* Scroll down key presed */
      PageDown();
      handled = true;
    }
  }
  else if (event->eType == menuEvent){ /* Menu event */
    switch (event->data.menu.itemID){
     case 3601: /* about */
      frm = FrmInitForm(3000);
      FrmDoDialog(frm);
      FrmDeleteForm(frm);
      break;
     case 3602:    /* Go Start Page */
      Page=1;
      drawBitmap(14, 25, 7000+Page);
      break;
     case 3603:    /* Back */
      PageDown();
      break;
     case 3604:    /* Next */
      PageUp();
      break;
     case 3605:    /* Sound ON */
      SoundSW=ON;
      break;
     case 3606:    /* Sound OFF */
      SoundSW=OFF;
      break;
    }
    handled = true;
  }
  else if(event->eType == nilEvent){
    handled = true;
  }
  return handled;
}

 

さぁ、コンパイルして実行させてみてください。
メニューに以下のように新しいプルダウンメニューが追加され、音を出したり止めたりできるはずです。

 次は設定条件等を保存する方法について説明します。