今回のサンプルです。
// sample14.cpp
#include <Application.h> // BApplicationを使うために必要
#include <Window.h> // BWindowを使うために必要
#include <View.h> // BViewを使うために必要
#include <Alert.h> // BAlertを使うために必要
#include <Button.h> // BButtonを使うために必要
#include <Box.h> // BBoxを使うために必要
#include <StringView.h> // BStringViewを使うために必要
#include <ListItem.h> // BStringItemを使うために必要
#include <Directory.h> // BDirectoryを使うために必要
#include <Entry.h> // entry_refを使うために必要
#include <ScrollView.h> // BScrollViewを使うために必要
#include <OutlineListView.h> // BOutlineListViewを使うために必要
// クラスの前方宣言
class MyApp;
class MyWindow;
class MyView;
// メッセージ定数
const uint32 BUTTON_CLICKED = 'bucl';
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* message);
private:
BStringView* m_string_view; // 左上の文字列
BScrollView* m_scroll_view; // スクロールビュー
BBox* m_box; // 装飾としてのBBox
BButton* m_button; // ボタン
BOutlineListView* m_outline_list_view; // ディレクトリの内容一覧をあらわす、OutlineListView
void AddAllFiles(BDirectory* entry,int level); // すべてのファイルを階層的にリストに追加
};
MyApp::MyApp()
:BApplication("application/x-vnd.big56-MyApp")
{
m_win = new MyWindow(BRect(100,100,350,380),"アウトラインビュー",B_TITLED_WINDOW,B_ASYNCHRONOUS_CONTROLS);
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,5,240,25),"theStringView","ディレクトリをドロップしてください");
AddChild(m_string_view);
m_box = new BBox(BRect(10,30,240,240));
m_box->SetLabel("ファイル一覧");
m_outline_list_view = new BOutlineListView(BRect(20-B_V_SCROLL_BAR_WIDTH/2,20,210-B_V_SCROLL_BAR_WIDTH/2,190),"theListView");
m_scroll_view = new BScrollView("theScrollView",m_outline_list_view,B_FOLLOW_LEFT | B_FOLLOW_TOP,
0,false,true);
m_box->AddChild(m_scroll_view); // スクロールビューの方を子供に加える
m_button = new BButton(BRect(140,250,240,270),"theButton",
"選択文字列の表示",new BMessage(BUTTON_CLICKED));
AddChild(m_box);
AddChild(m_button);
SetViewColor(200,200,200);
}
MyView::~MyView()
{
}
// ラジオボタンとボタンのターゲット変更
void MyView::AttachedToWindow()
{
m_button->SetTarget(this);
}
// メッセージ処理
void MyView::MessageReceived(BMessage* message)
{
switch(message->what)
{
case B_SIMPLE_DATA:
{
entry_ref ref;
message->FindRef("refs",&ref);
BDirectory dir(&ref);
// 受け取ったファイルがディレクトリで無かったら何もしない
if (dir.InitCheck() == B_OK)
{
BListItem* item; // リストの内容をすべて削除
while((item = m_outline_list_view->RemoveItem(static_cast<int32>(0) ) ) != NULL)
delete item;
AddAllFiles(&dir,0); // 階層構造のすべてのファイルをリストに追加
}
break;
}
case BUTTON_CLICKED:
{
if (m_outline_list_view->IsEmpty() ) break; // リストビューが空だったら何もしない
int32 index;
index = m_outline_list_view->CurrentSelection(); // 現在選択されている場所の位置を得る
if (index < 0) break; // なにも選択されていなかったら何もしない
BStringItem* selected_item;
selected_item = dynamic_cast<BStringItem*>(m_outline_list_view->ItemAt(index));
// ダウンキャストした結果が失敗したらなにもしない
if (selected_item != NULL)
{
// 現在選択されているものを表示
(new BAlert("Test",selected_item->Text(),"OK"))->Go();
}
break;
}
default:
BView::MessageReceived(message);
break;
}
}
// 階層構造のすべてのファイルを追加
void MyView::AddAllFiles(BDirectory* dir,int level)
{
char buffer[B_FILE_NAME_LENGTH]; // ファイル名を格納するバッファ
BEntry entry;
// ディレクトリの中のファイルを順々に得る
while (dir->GetNextEntry(&entry) == B_OK)
{
entry.GetName(buffer); // ファイル名の取得
if (entry.IsDirectory() ) // ディレクトリだったら、再帰呼び出し
{
// ディレクトリは、三角印をつけて名前を追加
m_outline_list_view->AddItem(new BStringItem(buffer,level,true));
//レベル階層を一段深くして、ディレクトリの内容を追加する再帰呼び出し
BDirectory dir2(&entry);
AddAllFiles(&dir2,level+1);
}
else //通常のファイルの処理
{
// ファイルの名前を追加
m_outline_list_view->AddItem(new BStringItem(buffer,level,false));
}
}
}
int main(int argc,char** argv)
{
MyApp app;
app.Run();
return 0;
}
今回の実行結果です。
画面では、筆者の/boot/home/config/settings/をドロップした直後の画面です。
途中のディレクトリに対しては、折り畳んで表示しないことも可能です。
ちょうど、WindowsのExplorerのファイル一覧を思い浮かべてくれればいいかと思います。
下の画像は折り畳んだところです。
まず、OutlineListViewの構築についての話です。
m_outline_list_view = new BOutlineListView(BRect(20-B_V_SCROLL_BAR_WIDTH/2,20,210-B_V_SCROLL_BAR_WIDTH/2,190),"theListView");
例によって実際のコンストラクタの宣言はこのようになっています。
BOutlineListView(BRect frame, const char * name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE);
コンストラクタで指定出来るものは、
frame、name、resizeMask、flagsについては第4回のBViewの説明、
typeについては第14回のListViewをごらんください。
OutlineListViewは、基本的な使い方はBListViewと同じです。
今回のサンプルでも、基本的には前回とまったく同じ使い方をしています。
では、階層構造の深さ(レベル)や、折り畳める場所などはどうやってしていするのかというと、
BListItem(このサンプルではBStringItem)で指定します。
このオプションに関しては、第14回のBStringItemのコンストラクタの引数、
levelとexpandedが重要になってきます。
expandedは、折畳み矢印をつけるかどうかのフラグ、levelは階層レベルです。(一番上のレベルは0、以下1,2,3と増えていく)
さて、実際にリストにファイルをどんどん追加しているコードの部分を見てみましょう。
// 階層構造のすべてのファイルを追加
void MyView::AddAllFiles(BDirectory* dir,int level)
{
char buffer[B_FILE_NAME_LENGTH]; // ファイル名を格納するバッファ
BEntry entry;
// ディレクトリの中のファイルを順々に得る
while (dir->GetNextEntry(&entry) == B_OK)
{
entry.GetName(buffer); // ファイル名の取得
if (entry.IsDirectory() ) // ディレクトリだったら、再帰呼び出し
{
// ディレクトリは、三角印をつけて名前を追加
m_outline_list_view->AddItem(new BStringItem(buffer,level,true));
//レベル階層を一段深くして、ディレクトリの内容を追加する再帰呼び出し
BDirectory dir2(&entry);
AddAllFiles(&dir2,level+1);
}
else //通常のファイルの処理
{
// ファイルの名前を追加
m_outline_list_view->AddItem(new BStringItem(buffer,level,false));
}
}
}
このコードでは、ディレクトリであるか同化の判定を、BStatable::IsDirectory()関数で判定しています。
BStatableはBEntryの基底クラスで、以下のような操作が出来ます。
| 宣言 | 説明 |
|---|---|
| GetCreationTime(time_t* ctime) SetCreationTime(time_t ctime) | ファイルの作成時間の取得と設定 |
| GetModificationTime(time_t* mtime) SetModificationTime(time_t mtime) | ファイルの最終更新時間の取得と設定 |
| GetOwner(uid_t *owner) SetOwner(uid_t owner) | ファイルの所有者のIDの取得と設定 |
| GetGroup(gid_t *group) SetGroup(gid_t group) | ファイルのグループIDの取得と設定 |
| GetPermissions(mode_t *perms) SetPermissions(mode_t perms) | ファイルのパーミッションの取得と設定 |
| GetSize(off_t *size) | ファイルサイズの取得 |
| GetStat(struct stat* st) | stat構造体の取得 |
| GetNodeRef(node_ref* nref) | node_ref構造体の取得 |
| IsFile() IsDirectory() IsSymLink() | ファイルかディレクトリかシンボリックリンクかを調べ、結果をtrueまたはfalseで返す |
次に、ディレクトリだったら、expandフラグをtrueにしてBStringItemを構築し、
そのディレクトリ以下を調べるために、レベルを一段深くして再帰呼び出しを用いています。
ディレクトリでなかったら、ファイルの名前を普通に追加するだけです。
しかし、この時はexpandフラグはfalseにします。
今回の内容は、BOutlineListViewとBStatableについてでした。
本来であればBOutlineListViewは階層構造をうまくコントロールするいろんなメンバ関数があるのですが、
興味があればBeBook等で調べて見てください。
今回のサンプルはルートに近いディレクトリをドロップすると、応答がない状態になるなどの問題点を抱えていますので、
改善点なども考えてみるのもいいかもしれません。
|
|||
|
|