Lesson 9:ファイルを読み込む


 今回はファイルの読み込みに挑戦してみます。ホントは保存もやりたかったのですが、そこまでやる時間が無かったので保存は次回にまわします。

 ファイルを読み込むには当然読み込むファイルを選択する必要があります。MS-Windowsにコモンダイアログがあるように、BeOSにもファイルを選択する画面があらかじめ準備されています。今回はこれを使用してフィル選択を行いたいと思います。
 前回、FileメニューにOpenを作成しましたので、Openを選択されたらファイル選択画面を表示してファイルの読み込みを行うようにしましょう。

 ファイル選択画面ですが、いつものようにBeBookで探していくと、BFilePanelというクラスが見つかりました。ただ、今まではThe Interface Kitから探していましたが、BFilePanelはThe Storage Kitに属しています。説明を読むと(画像まであるので間違いなく)ファイル選択画面を表示するクラスのようです。
 BFilePanelにShowという関数がありますので、画面を表示するにはこの関数で良いようです。では、選択したファイル名はどのようにして受け取る事ができるか、説明を読んでいくと"refs"というキーワードが頻繁に出てきます。このrefsを調べてみると、BFilePanelが送信するメッセージにのせる、entry_refという型の情報で、選択情報が格納されているようです。ですから、選択したファイルの情報を受け取るには、BFilePanelからのメッセージを処理して、refsの情報を取得すれば良いようです。

 まずはBFilePanelを表示するところまでを作成してみましょう。
 今回は後々の事を考えてopen_filepanelというBFilePanelをBTinyEditorAppクラス内に定義して使用します。

/**** ファイル名 : BTinyEditor.h ****/

#ifndef BTINYEDITORAPP 
#define BTINYEDITORAPP 
//--------------------------------------------------------------------- 
#include <Be.h> 
#include "MainWindow.h" 
//--------------------------------------------------------------------- 
#define APPLICATION_SIGNATURE   "application/x-vnd.vow-betinyeditor" 
//--------------------------------------------------------------------- 
class BTinyEditorApp : public BApplication 
{ 
private:
    BFilePanel *open_filepanel;
public: 
    BTinyEditorApp() 
        :BApplication(APPLICATION_SIGNATURE) 
    { 
        BEditorWindow *mainwnd=new BEditorWindow( 
            BRect(MAINWINDOW_POSITION_LEFT,MAINWINDOW_POSITION_TOP, 
                  MAINWINDOW_POSITION_WIDTH+MAINWINDOW_POSITION_LEFT-1, 
                  MAINWINDOW_POSITION_HEIGHT+MAINWINDOW_POSITION_TOP-1), 
            MAINWINDOW_TITLE);
        
        open_filepanel= new BFilePanel(); 
        mainwnd->Show();
    };
    //----------------------------------------------------------------- 
    ~BTinyEditorApp()
    {
        delete open_filepanel;
    };
    //----------------------------------------------------------------- 
    void MessageReceived(BMessage *msg) 
    { 
        switch(msg->what) 
        {        
            case MSG_OPEN:
                open_filepanel->Show();
                break; 
            default: 
                BApplication::MessageReceived(msg); 
        } 
    }; 
}; 
//--------------------------------------------------------------------- 
#endif 

 privateでopen_filepanelを定義しておいて、コンストラクタで実体を作成しておきます。デストラクタも定義しておき、この中でopen_filepanelの削除を行います。
 open_filepanelを表示するトリガとして前回定義だけしていたMSG_OPENを使用します。このMSG_OPENを受け取ったらopen_filepanelを表示するようにMessageReceived関数の中を書き換えておきます。

次にこのMSG_OPENを送信する部分の作成が必要ですが、これは前回で既にFileメニューのOpenに定義していますので、これが使用できます。ただ、このまま使用してしまうとメッセージの送信先がBEditorWindowになってしまいますので、SetTarget関数でメッセージの送信先をbe_appに変更する必要があります。

/**** ファイル名 : MainWindow.cpp ****/

//--------------------------------------------------------------------- 
BEditorView::BEditorView(BRect frame) 
    :BView(frame,"beditorview",B_FOLLOW_ALL,B_WILL_DRAW) 
{ 
    BRect viewrect(Bounds()); 
    BMenuBar *mainmenu=new BMenuBar(BRect(0,0,viewrect.right, 
                                          be_plain_font->Size()*2), 
                                    "mainmenubar"); 
    AddChild(mainmenu); 

    memo=new BMemoView(BRect(0,be_plain_font->Size()*2, 
                 viewrect.right-B_V_SCROLL_BAR_WIDTH, 
                 viewrect.bottom-B_H_SCROLL_BAR_HEIGHT), 
               "memo",B_FOLLOW_ALL); 
    BScrollView *scr=new BScrollView("memoscroll",memo, 
                     B_FOLLOW_ALL,0,true,true); 
    AddChild(scr); 

    BMenu *filemenu=new BMenu("File"); 
    filemenu->AddItem(new BMenuItem("Open...",new BMessage(MSG_OPEN)));
    filemenu->ItemAt(0)->SetTarget(be_app); 
    filemenu->AddItem(new BMenuItem("Save",new BMessage(MSG_SAVE))); 
    filemenu->AddItem(new BMenuItem("Save As...",new BMessage(MSG_SAVEAS))); 
    filemenu->AddSeparatorItem(); 
    filemenu->AddItem(new BMenuItem("Quit",new BMessage(B_QUIT_REQUESTED))); 
    mainmenu->AddItem(filemenu); 

    BMenu *editmenu=new BMenu("Edit"); 
    editmenu->AddItem(new BMenuItem("Undo",new BMessage(B_UNDO))); 
    editmenu->AddSeparatorItem(); 
    editmenu->AddItem(new BMenuItem("Copy",new BMessage(B_COPY))); 
    editmenu->AddItem(new BMenuItem("Cut",new BMessage(B_CUT))); 
    editmenu->AddItem(new BMenuItem("Paste",new BMessage(B_PASTE))); 
    editmenu->AddItem(new BMenuItem("Select All",new BMessage(B_SELECT_ALL))); 
    mainmenu->AddItem(editmenu); 

    memo->SetDoesUndo(true); 
} 
//--------------------------------------------------------------------- 

 実際に動作させてみると、FileメニューのOpenを選択するとファイル選択の画面が表示されます。
 前回はSetTargetがうまく動作しませんでしたが、今回はうまく動作しました。(なぜでしょう??)

 あ、そうそう、BFilePanelクラスを利用するには、libtrackerというライブラリをプロジェクトに追加する必要があります。ライブラリは/boot/develop/lib/の中にありますので、libtrackerを追加しておいてください。

 画面が表示できたら次は選択した情報の取得とファイル読み込みです。
 選択した情報はメッセージに"refs"の名称でのっているわけですから、このメッセージを受信する関数を用意すればいいはずです。そのためにRefsReceivedという関数があらかじめ定義されていますので、その関数で処理してやれば良いようです。
 ファイルの読み込みですが、ファイルを読み込むにはどんな方法があるかを、まず考えてみましょう。昔ながらのfopenやfread等を使用する方法、もっと基本的なopen等を使用する方法もありますが、BeOSでもAPIでファイルの読み書きを行うBFileクラスが準備されていますので、今回はそれを使用しましょう。
 BFileでファイルを扱うにはファイルの情報をBEntryクラスに入れておく必要があるようで、BEntryクラスにはentry_refから情報を取得する仕組みが用意されています。メッセージからBEntryクラスに情報を取り込むまでをRefsReceived関数で行い、実際のファイルの読み込みは、BEditorWindowにファイル読み込みの関数「OpenFile」を作成してそこで行うようにしてみます。

/**** ファイル名 : BTinyEditor.h ****/

    void RefsReceived(BMessage *message)
    {
        type_code ref_type;
        int32 ref_count;
        entry_ref ref;
        BEntry entry;
        
        message->GetInfo("refs", &ref_type,&ref_count);
        for (int i=0;i<ref_count;i++)
        {
            message->FindRef("refs",i,&ref);
            if(entry.SetTo(&ref)==B_OK)
            {
                WindowAt(0)->Lock();
                ((BEditorWindow *)WindowAt(0))->OpenFile(&entry);
                WindowAt(0)->Unlock();
                return;
            }
        }
    }

 選択情報の取得ですが、まず
message->GetInfo("refs", &ref_type,&ref_count);
で"refs"の情報からファイル名の個数を取得します。
 iをインデックスとして
message->FindRef("refs",i,&ref);
でファイル名の情報を取り出しSetTo関数でentryにセットしたら、BEditorWindowのOpenFile関数を呼び出します。ここで注意しなければならないのは、OpenFile関数を呼び出す手前で、そのウィンドウをLock関数でロックしている点です。
 OpenFile関数を呼び出す前にロックしているのは、OpenFile関数でファイル読み込みを行っている間、他の要因で対象としているウィンドウが操作される事を防止するためです。(ファイル読み込み中にウィンドウを破棄されたりすると困りますからね。)

/**** ファイル名 : MainWindow.h ****/

//--------------------------------------------------------------------- 
class BEditorWindow : public BWindow 
{ 
public: 
    BEditorView *mainview; 
    //----------------------------------------------------------------- 
    BEditorWindow(BRect frame,const char *title); 
    virtual void MessageReceived(BMessage *msg); 
    void OpenFile(BEntry *entry);
    //----------------------------------------------------------------- 
    bool QuitRequested() 
    { 
        be_app->PostMessage(B_QUIT_REQUESTED); 
        return true; 
    }; 
}; 
//--------------------------------------------------------------------- 

/**** ファイル名 : MainWindow.cpp ****/

//--------------------------------------------------------------------- 
void BEditorWindow::OpenFile(BEntry *entry)
{
    if(entry->Exists())
    {
        BFile fil;
        off_t size;
                
        fil.SetTo(entry,B_READ_ONLY);
        fil.GetSize(&size);
        ((BTextView *)FindView("memo"))->SetText(&fil,0,size);
    }
}
//--------------------------------------------------------------------- 

 実際にファイルから読み込みを行うOpenFile関数ですが、まず、BEntryクラスのExists関数でファイルが存在しているかを確認し、存在する場合のみ読み込みを行うようにしています。
 BMemoViewにファイルの内容を反映させる方法ですが、BTextViewのメンバ関数を調べてみると、SetText関数にBFileから情報を取得するものがある事がわかりましたので、それを使用しています。

 これをコンパイルして実行すると、今度は選択したファイルを読み込んで表示します。

 今回はファイルの読み込みまでしかできませんでした。次回はファイルの保存に挑戦してみたいと思います。ただ、今日(3/28)はBeOS Personal Editionのダウンロード開始日ですので、今週はダウンロードとセットアップだけで終わってしまうかもしれませんが・・・。

ソースリスト
圧縮ファイル
R5 Intel環境で確認
BTinyEditor20000328.zip
ソースファイル BTinyEditor.h
BMemoView.cpp
BMemoView.h
main.cpp
MainWindow.cpp
MainWindow.h

次の項目へ

トップページへ戻る