第9回 dragしたいお年頃


えー、というわけで、今回はdrugならぬdrag & dropです。
実はBeOS標準のsample-codeにDropWorldというのがありまして、
今回のサンプルはそれとあまり変わらなくなってしまったのですが、
次回に繋げるためのサンプルですので、ご了承ください。

あと、今回はBStringViewとBFontという二つのクラスを紹介します。
BStringViewはビューに描く文字列のクラスです。
BView::Drawをオーバーライドしていちいち書き直す必要がないのが特徴です。
BFontはその名の通りフォントを示すクラスです。
今回はBFontを使用して、表示する文字列の長さに応じて、BStringViewの大きさを変更しています。


さて今回のソース全体です。

// sample07.cpp

#include <Application.h>        // BApplicationを使うために必要
#include <Window.h>             // BWindowを使うために必要
#include <View.h>               // BViewを使うために必要
#include <Alert.h>			// BAlertを使うために必要
#include <StringView.h>		// BStringViewを使うために必要
#include <Font.h>			// BFontを使うために必要
#include <Entry.h>			// entry_ref構造体を使うために必要

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

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 MessageReceived(BMessage* message);
private:
	void AutoFitStringView(const char* string);  // BStringViewを適切にリサイズする
	BStringView* m_string_view; // 表示する文字列
};

MyApp::MyApp()
      :BApplication("application/x-vnd.big56-MyApp")
{
	m_win = new MyWindow(BRect(100,100,300,150),"ドラッグ&ドロップ",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)
{
	m_string_view = new BStringView(BRect(10,10,150,30),"thStringView","ファイルをドロップしてください");
	AutoFitStringView("ファイルをドロップしてください");
	
	AddChild(m_string_view);
}

MyView::~MyView()
{
}

void MyView::MessageReceived(BMessage* message)
{
	entry_ref ref; // ファイルを表す構造体
	
	switch(message->what)
	{
	// ファイルがドラッグされたときに、ビューはB_SIMPLE_DATAというメッセージを受け取る
	// その時、"refs"というキーで、ファイルを示すentry_refという構造体がメッセージに含まれる
	// entry_refのnameというフィールドにファイル名(フルパスではない)が入っている
	case B_SIMPLE_DATA:
		// entry_ref構造体が正常に取得できたら処理を開始
		if (message->FindRef("refs",&ref) == B_OK)		
		{
			AutoFitStringView(ref.name);
			m_string_view->SetText(ref.name);
		}
		break;
	default: 
		BView::MessageReceived(message);
		break;
	}
}

// 与えられた文字列に対して、m_string_viewを適切な長さに設定する
void MyView::AutoFitStringView(const char* string)
{
	BFont font(be_plain_font);	// be_plain_fontはユーザーがシステム設定しているフォント
	font_height f_height;

	float width,height; // 文字の幅と高さ

	// StringWidthで文字列の幅の長さを取得出来る
	width = font.StringWidth(string);  

	// 文字の高さはまずfont_height構造体を取得する必要がある
	font.GetHeight(&f_height);   

	// アセントどデセントを足した値がフォントの高さ	
	height = f_height.ascent + f_height.descent;  

	m_string_view->ResizeTo(width,height);
}

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

今回の実行結果です。

実行結果初期画面

最初はこのような画面が表示されますが、ウィンドウ内にファイルをドラッグすると次の様になります。

実行結果ファイルドラッグ後

といった感じに、ファイル名が表示されます。


まず最初に、表示する文字列に関する部分、BStringViewに関する場所を見てみましょう。


	m_string_view = new BStringView(BRect(10,10,150,30),"thStringView","ファイルをドロップしてください");
	AutoFitStringView("ファイルをドロップしてください");

BStringViewはビューに表示する文字列を扱うクラスです。
第4回でBView::DrawString()関数というもので、文字列を描画しましたが、
このBStringViewはそれに変わるものとして考えてもらって構いません。
これは、Windowsのコントロールの名前を借りていうならば、ラベルに当たるものです。

BStringViewのコンストラクタの引数並びは次の様になっております。

BStringView(BRect frame, const char *name, const char *text, 		uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, 
	    uint32 flags = B_WILL_DRAW)

コンストラクタでは、resizingModeとflagsが=(イコール)で結ばれていますが、
これは引数を指定しないと、デフォルトでその値になることを示しています。

BStringViewのコンストラクタではBMessageを指定していませんが、
BStringViewはメッセージを送信することはありません。ただ画面に表示されるのみです。
コンストラクタの引数では特に目新しいものを指定していないので、そこまで難しくないと思います。

さて、BStringViewを構築はしましたが、今回のサンプルでは文字列の長さに合わせて
適切な大きさにサイズ変更しています。
これをしないと、文字列が途中で切れたりすることになります。

「え〜それだったら、BView::DrawString()関数の方が大きさを考えなくてすむので楽じゃん」
と思われる方もいると思いますが、たいていのアプリケーションでは、
コンストラクタ時に表示する文字列を決めたらその後変わることがほとんどないのと、
サンプルではBFontの使い方の一例を示すために、わざとサイズ変更をやっています。
多分こんなコーディングはまれだと思います。


さて、BStringViewのサイズ変更をする関数、AutoFitStringView()関数を見てみましょう。
これは、MessageReceived()関数などのBeOSのシステムで定義されている関数ではなく、
自分で勝手に定義した関数です。


// 与えられた文字列に対して、m_string_viewを適切な長さに設定する
void MyView::AutoFitStringView(const char* string)
{
	BFont font(be_plain_font);	// be_plain_fontはユーザーがシステム設定しているフォント
	font_height f_height;

	float width,height; // 文字の幅と高さ

	// StringWidthで文字列の幅の長さを取得出来る
	width = font.StringWidth(string);  

	// 文字の高さはまずfont_height構造体を取得する必要がある
	font.GetHeight(&f_height);   

	// アセントどデセントを足した値がフォントの高さ	
	height = f_height.ascent + f_height.descent;  

	m_string_view->ResizeTo(width,height);
}

BFontは文字のフォントを代表するクラスです。
BFontの機能としては、次の表に示すものがあります。

ここにあげたのはほんの一例で、特に文字の印刷や描画の際の大きさの設定に関しては
非常に多くの機能を持っています。

BFontのコンストラクタではbe_plain_fontを指定しています。
これは[Preference] - [Fonts]でユーザーが設定したフォントです。

Fonts画面

他に、Bold Fontを指定したい場合はbe_bold_fontを、
Fixed fontを指定したい場合は、be_fixed_font
それぞれコンストラクタに指定します。
これらは、BFont* 型で、グローバルポインタとしてBFont.hのファイル内で宣言されています。

次に文字の大きさを決める、StringWidthとGetHeight関数の宣言を見てみましょう。
float StringWidth(const char *string) const;
void GetHeight(font_height *height) const;

StringWidthでは、文字列を与えると、それに応じた幅の大きさがfloat型で返ってきます。
この値は同じ文字列でも、フォントの種類や大きさによって当然変わってきます。

GetHeight関数は、font_height構造体を通して、文字列の高さを取得します。
font_height構造体には次の3つのfloat型のフィールドがあります。

フィールド名説明
ascnet文字がベースラインよりどれだけ上に伸びるか
descnet文字がベースラインよりどれだけ下に下がるか
leading行間の長さ
ここでは、文字そのもの高さを取得したいなので、ascentとdescentフィールドを足します。

最後にBView::ResizeTo()関数で、BStringViewの大きさをリサイズします。
BStringViewもビューの一種なのでBViewからの派生クラスなわけですが、
BViewで定義されているResizeTo()関数によって、どの種類のビューでもサイズ変更が可能になっています。

	void ResizeTo(float width, float height)

ResizeTo()関数では、横の長さ(width)と高さ(height)を指定します。
そうすると、ビューの左上の点はそのままですが、大きさが変わります。


さて、やっと今回のメイン、ドロップされたファイルに対する処理を見てみましょう。


	entry_ref ref; // ファイルを表す構造体
	
	switch(message->what)
	{
	// ファイルがドラッグされたときに、ビューはB_SIMPLE_DATAというメッセージを受け取る
	// その時、"refs"というキーで、ファイルを示すentry_refという構造体がメッセージに含まれる
	// entry_refのnameというフィールドにファイル名(フルパスではない)が入っている
	case B_SIMPLE_DATA:
		// entry_ref構造体が正常に取得できたら処理を開始
		if (message->FindRef("refs",&ref) == B_OK)		
		{
			AutoFitStringView(ref.name);
			m_string_view->SetText(ref.name);
		}
		break;

ファイルがドロップされた時は、B_SIMPLE_DATAというメッセージを受け取ります。
その時に、"refs"にドロップされたファイルの情報が入っているので、
ファイル名取得のためにそれを使用します。

第7回でBMessageのFindRef()関数は、entry_ref構造体を見つけだすために使用すると書きましたが
entry_ref構造体とは、ファイルを表す構造体であり、イメージとしてはC言語のFILE* や、
UNIXのファイルディスクリプタ(こっちの方が近いかも)にあたります。
entry_refはBEntryやBFile、BDirectoryといったクラスを通して使うことがほとんどですが、
ファイル名の取得だけならば、char* 型のnameフィールドにアクセスすればいいです。

このサンプルでは、
FindRefでentry_refを取得→BStringViewのサイズ変更→BStringViewの文字列変更
という流れになっています。
BStringViewのSetTexi()関数は今回初めて出てきましたが、引数に変更する文字列を指定するだけです。
サンプルを見ればわかると思います。


今回はBStringViewとBFontとB_SIMPLE_DATAという3部作でお送りしましたがいかがでしたでしょうか?
最近は1回ごとにやる内容が多くなっているような気がします。
なるべくわかりやすくをモットーに書いていますが、疑問点などあったらメールください。
適宜補完して書いていきたいと思いますので。

さて次回はこのアプリを元に簡易音楽ファイル再生プレイヤーを作ってみたいと思います。

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

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