第12回 メニューについて

今回はメニューです。
メニューってのは、ウィンドウの上の方にあって、
「ファイル」とか「ヘルプ」とか書いてあるやつのことです。

メニューの作成には、BMenuBarとBMenuとBMenuItemというクラスが密接にかかわっています。
基本的には、BMenuBarの中にBMenuが複数あり、
BMenuの中にBMenuItemが複数あるといった、ネスト構造になっています。


// sample10.cpp

#include <Application.h>        // BApplicationを使うために必要
#include <Window.h>             // BWindowを使うために必要
#include <View.h>               // BViewを使うために必要
#include <Alert.h>			  // BAlertを使うために必要
#include <MenuBar.h>           // BMenuBarを使うために必要
#include <Menu.h>			 // BMenuを使うために必要
#include <MenuItem.h>		 // BMenuItemを使うために必要

// クラスの前方宣言
class MyApp;
class MyWindow;
class MyView;

// メッセージ定数
const uint32 QUIT_WITH_CHECK = 'qwch';
const uint32 PLEASE_HELP = 'plhe';

class MyApp : public BApplication
{
public:
	MyApp();
private:
	MyWindow* m_win;
};

class MyWindow : public BWindow
{
public:
	MyWindow(BRect frame,const char* title,window_type type,uint32 flags);
	virtual bool QuitRequested();	// 終了が要求されたときに呼ばれる関数
private:
	MyView* m_view;
};
 
class MyView : public BView
{
public:
	MyView(BRect frame,const char *name,uint32 resizingMode,uint32 flags);
	~MyView();
	virtual void AttachedToWindow();	// ビューがウィンドウに取り付けられたとき(子供として登録された後)呼ばれる関数
	virtual void MessageReceived(BMessage* _msg);
private:
	void InitMenu();
	BMenuBar* m_menubar;         // メニューバー
};

MyApp::MyApp()
      :BApplication("application/x-vnd.big56-MyApp")
{
	m_win = new MyWindow(BRect(100,100,300,170),"メニュー",B_TITLED_WINDOW,0);
	m_win->Show();
}

MyWindow::MyWindow(BRect frame,const char* title,window_type type,uint32 flags)
		:BWindow(frame,title,type,flags)
{
	frame.OffsetTo(0,0);  // 与えられたBRectの左上が(0,0)になるようにする

	m_view = new MyView(frame,"theView",B_FOLLOW_ALL_SIDES,B_WILL_DRAW);
	AddChild(m_view);	
}

bool MyWindow::QuitRequested()
{
// アプリケーションを終了する
	be_app->Quit();
	return true;
}

MyView::MyView(BRect frame,const char* title,uint32 resizingMode,uint32 flags)
	  :BView(frame,title,resizingMode,flags)
{
}

MyView::~MyView()
{
}

void MyView::AttachedToWindow()
{
	InitMenu();
}

// メニューの初期化
void MyView::InitMenu()
{
	m_menubar = new BMenuBar(BRect(0,0,100,20),"theMenu");

	BMenu* p_menu;
	BMenu* p_menu2;
	BMenuItem* p_menuitem;
	
	p_menu = new BMenu("ファイル");
	p_menuitem = new BMenuItem("終了",new BMessage(B_QUIT_REQUESTED),'Q');
	p_menu->AddItem(p_menuitem);	  // 「終了」の追加

	// 仕切り線の追加
	p_menu->AddSeparatorItem();

	// ネストした、「終了しようかな?」メニューの追加
	p_menu2 = new BMenu("終了しようかな?");
	p_menuitem = new BMenuItem("確認して終了",new BMessage(QUIT_WITH_CHECK));
	p_menuitem->SetTarget(this);
	p_menu2->AddItem(p_menuitem);  // 「確認して終了」の追加

	p_menuitem = new BMenuItem("確認せずに終了",new BMessage(B_QUIT_REQUESTED));
	p_menu2->AddItem(p_menuitem);

	p_menu->AddItem(p_menu2);  // 「終了しようかな?」メニューの追加

	m_menubar->AddItem(p_menu); // 「ファイル」全体の追加

	p_menu = new BMenu("ダミー");
	m_menubar->AddItem(p_menu); // ダミーメニューの追加

	p_menuitem = new BMenuItem("ヘルプ",new BMessage(PLEASE_HELP));
	p_menuitem->SetTarget(this);

	m_menubar->AddItem(p_menuitem); // 「ヘルプ」の追加

	
	AddChild(m_menubar);  // メニューバー全体をビューの子供にする
}

// ビューの処理関数はチェックボックスが押されたときの処理を記述する
void MyView::MessageReceived(BMessage* message)
{
	BAlert* alert;
	int32 index;
	
	switch(message->what)
	{
	case QUIT_WITH_CHECK:
		alert = new BAlert("quit_alert","終了しますか?","はい","いいえ");
		
		// アラートボックスを表示して、押されたボタンの番号を調べる
		index = alert->Go();

		// 「はい」が押されたらウィンドウにB_QUIT_REQUESTEDを送信
		if (index == 0) Window()->PostMessage(B_QUIT_REQUESTED);

		break;
	case PLEASE_HELP:
		(new BAlert("help","Please Help me","OK"))->Go();
		break;	
	default: 
		BView::MessageReceived(message);
		break;
	}
}


int main(int argc,char** argv)
{
 	MyApp app;
	app.Run();
	return 0;
}

今回のアプリケーションの実行結果です。

実行結果

前回のアプリより随分とシンプルになりました。
今回はメニューをつけただけなので、解説項目も少ないです。

ファイルメニューをクリックすると次の様になります。

ファイルメニューをクリックしたところ

ダミーメニューはメニューアイテム項目を設定していない、BMenuです。
クリックすると次の様に"<empty>"と表示されます。

ダミーメニューをクリックしたところ

ヘルプをクリックした時には・・・


今回は、メニューを初期化する関数InitMenu()関数が最重要です。
まずは、メニューバー、BMenuBarの構築についてです。

m_menubar = new BMenuBar(BRect(0,0,100,20),"theMenu");

BMenuBarの実際のコンストラクタは次の様になっています。

BMenuBar(BRect frame,
	const char *title,
	uint32 resizeMask =
	B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
	menu_layout layout = B_ITEMS_IN_ROW,
	bool resizeToFit = true);

指定するものは

となっています。
frameに関しては、resizeToFitをtrueに指定した場合、左上の座標しか気にしないようです。
ですから、メニューをウィンドウの端にくっつけないメニューも可能です。
さらに注目なのが第4引数のlayoutで、
BeOSでは縦にメニューを配置することも出来るようになっています。
layoutに指定できる引数は次の通りです。

説明
B_ITEMS_IN_ROWメニューを横に並べる
B_ITEMS_IN_COLUMNメニューを縦に並べる
B_ITEMS_IN_MATRIX格子状に並べる(現在は設定不可)

B_ITEMS_IN_COLUMNを指定すると、メニューは次のような感じになります。

B_ITEMS_IN_COLUMN指定時のウィンドウ

B_ITEMS_IN_MATRIXは試しにやってみたところ、プログラム自体が落ちてしまいました。

そして次に、BMenuの構築です。今回のプログラムでは、一時領域として、BMenuのポインタ2つと
BMenuItemのポインタを宣言しています。

BMenu* p_menu;
BMenu* p_menu2;
BMenuItem* p_menuitem;

そして次に、BMenuを構築しています。

p_menu = new BMenu("ファイル");

BMenuの実際のコンストラクタです。

BMenu(const char *title,
	menu_layout layout = B_ITEMS_IN_COLUMN);

第1引数にはビューの名前、第2引数はメニューが横に伸びて行くのが、縦に伸びていくのかを指定します。
第2引数に関しては、BMenuItemのlayoutと同じ引数が指定出来ます。
デフォルトでは、B_ITEMS_IN_COLUMN(縦に伸びる)が指定されていますが、これはどういうことかというと、
「ファイル」メニューをクリックすると、「終了」などの項目は下の方に列挙されて出てきます。
これが、B_ITEMS_IN_ROWだと、右の方に列挙されて出てきます。
(実際には、「ファイル」と書かれているすぐ下から、右側に向かって列挙される)

言葉より画像にして出したほうが分かりやすいと思うので、
試しにnew BMenu("ファイル",B_ITEMS_IN_ROW)とすると

BMenuをB_ITEMS_IN_ROWにしたところ

となります。見づらいですね。

次に、BMenuItemの構築です。

p_menuitem = new BMenuItem("終了",new BMessage(B_QUIT_REQUESTED),'Q');

BMenuItemの実際のコンストラクタです。

BMenuItem(const char *label,
	BMessage *message,
	char shortcut = 0,
	uint32 modifiers = 0);

指定するものは、

となっています。
labelについては説明不要だと思いますが、messageはクリックされた時に、
所属するウィンドウに送信するメッセージの種類を指定します。
送信先は、ボタンチェックボックスと同様に、
SetTarget()関数で変えることが出来ます。
以前の繰り返しになりますが、SetTarget()関数はビューのコンストラクタ内で行うと失敗します。

shortcutには、いわゆるショートカットに使用するキーボードのキーを指定します。
この場合でいうと、ショートカットキーとQと同時に押すと、このメニューがクリックされた(終了させた)のと
同じ効果を出すことが出来ます。
(ちなみに終了はわざわざ指定しなくても、システム側でショートカット+Qが押されると、終了しますが
メニューの右側にショートカットキーが表示されるので、ユーザーに対して分かりやすいという効果があります。)
コマンドキーとは、Beメニューの[Preference]-[Menu]で設定出来るキーです。

Menu画面

私の場合、一般的な「コピー」や「貼り付け」などの動作をWindowsと同じにするために、
ショートカットキーをコントロールキーに割り当てています。

次に、modifierには、ショートカットに使用する装飾キー(ShiftやAltやCtrlなど)を指定します。
指定できる値は次の通りです。

説明
B_SHIFT_KEYシフトキー
B_CONTROL_KEYコントロールキー(後述)
B_OPTION_KEYオプションキー(Intel版はWIndowsキー)

ここでコントロールキーとは、Ctrlをショートカットキーに指定していたら、Altキーで、
Altキーをショートカットキーに指定していたらCtrlキーのことになります。
Macの場合については手元にMacが無いのでわからないです。すみません。

これで、BMenuBarとBMenuとBMenuItemのインスタンスの構築が出来るようになりました。
あとは、これらを適切にAddItem()関数を使って、追加していくだけです。
最初の方でメニューはネスト構造といいましたが、BMenu::AddItem関数を何回か呼び出して、
BMenuItemを複数持つBMenuを作成して、そのBMenuをBMenuBar::AddItem関数で
BMenuBarに追加するといった感じになります。

言葉で説明すると難しいのですが、プログラムと実行結果を見比べれば、
雰囲気だけはわかっていただけるのではないかと思います。

AddItemについてもう少し詳しく説明すると、BMenuのAddItemは次の様になっています。

bool	AddItem(BMenuItem *item);
bool	AddItem(BMenuItem *item, int32 index);
bool	AddItem(BMenu *menu, int32 index);
bool	AddItem(BMenu *menu, BRect frame);

BMenuItemを指定するバージョンと、BMenuを指定するバージョンがあります。
今回の「終了しようかな?」メニューなど、ネスト構造を作りたい場合は、
BMenuのポインタをAddItemで指定して実現させます。

あと、indexを指定するバージョンと指定しないバージョンがありますが、
indexを指定した場合は、メニューがindex番目に追加されますが、
指定しない場合はメニューが最後に追加されます。

あとは、仕切り線の追加についてです。

// 仕切り線の追加
p_menu->AddSeparatorItem();

BMenu::AddSeparatorItem()関数を呼び出すと、メニューの最後に仕切り線が追加されます。
この仕切り線は、先程の[Preference]-[Menu]のSeparator Styleで指定できるものと同じものが追加されます。


さて、次に「確認して終了する」を選んだ時の動作について説明します。

case QUIT_WITH_CHECK:
	alert = new BAlert("quit_alert","終了しますか?","はい","いいえ");
		
	// アラートボックスを表示して、押されたボタンの番号を調べる
	index = alert->Go();

	// 「はい」が押されたらウィンドウにB_QUIT_REQUESTEDを送信
	if (index == 0) Window()->PostMessage(B_QUIT_REQUESTED);

	break;

今までのBAlertを使用したコードとなんら変わりませんが、BAlert::Go()関数の戻り値を使用しています。
これは、第2回でもちょっと説明しましたが、BAlert:Go()では、
押されたボタンの番号が返ってきます。
今回は、左から「はい」、「いいえ」の順に並べていますので、「はい」が押されると、
0が返ってくるわけです。

「はい」が押された場合にのみ、B_QUIT_REQUESTEDを送信します。
「いいえ」が押されたときには何もしません。

今回はサンプルなので、このようなコードになりましたが、
実際、エディタなどで作成中の文章が保存されていない時の、終了確認などは、
BWindow::QuitRequested()関数内などでやるのが一般的だと思います。

case PLEASE_HELP:
	(new BAlert("help","Please Help me","OK"))->Go();
	break;

上の部分に「ヘルプ」ボタンが押されたときの処理が書いてあります。
今までやったBAlertと同じ処理なので説明は省略させていただきます。


さて、今回はメニューについて簡単に説明しました。
地味ですけど必ず書く部分です。
今回のサンプルで基本的なことは網羅していると思うので、書き方を忘れたときは
今回のサンプルを参考にしていただけると幸いです。

[<<前へ] [次へ>>] [戻る]

big56 big56@anet.ne.jp
給料前でお金がない・・ 給料前でお金がない・・ 海外旅行保険の加入はコチラ!
[PR] | ヒーリング会社案内 作成se 転職川口栃木荻窪池袋中国SEO対策消費者金融車 買取テンプレート沖縄旅行免許合宿二輪引越しプレゼントゴルフ会員権留学レーシックマッサージFXアフィリエイトFXホームページ制作デイトレードハワイ旅行タイバンコクハワイ レンタカーベスト ハワイ ホテル レーツバリ島Hawaii hotelsHawaii Activitiesbhhrハワイホテルテキスト広告
【運営会社「パラダイムシフト」サービス】 ハワイ現地オプショナルツアーリラックマ) - ビジネスクラス航空券 - 格安航空券(1) - 格安航空券(2) - 海外ホテル - 韓国旅行 - タイムシェア - ホテル 予約
無料ホームページ - 携帯ホームページ - 無料ホームページ作成 - レンタルサーバー - ブログ - ヴィラ - ハワイ コンドミニアム - バリ島 ホテル - プーケット ホテル - 旅行 口コミ - 旅行情報 - 国際電話 - ホノルルマラソン - 掲示板監視 - 風評被害 - ホテル比較 - ノースウェスト航空 - ファイナルチェッカー