Lesson 16:表示位置を変えてみる

 今までは、ウィンドウの表示位置をMainWindow.hで定数に定義した値で決めていました。このため、何度ウィンドウを作成しても、位置も大きさも同じように表示されていました。これではなんとなく面白くないですし、ウィンドウが完全に重なっているのでは、操作しにくい面もあります。
 そこで、ウィンドウの表示位置を新しいウィンドウを表示する毎に、少しずつずらして表示するようにしてみましょう。それと、ウィンドウの大きさを保存して、次に起動したときにも同じ大きさで表示できるようにします。

 まず、大きさを保存する部分を作成しましょう。もちろんファイルに保存するのですが、こういった場合にはどのようなファイルフォーマットで保存しましょうか。CSVやINIファイル(Windowsで良く利用される設定ファイル)といったテキストファイルベースの形式で保存するか、それとも独自のバイナリ形式で保存しましょうか。
 今回は、そのどちらも使用しません。今回設定を保存しておくファイルには、リソースファイルを使用してみます。
 リソースファイルにはIDと値を結び付けて保存する事が出来ます。何の設定を保存するのに、何番のIDを使用するかを、保存側と読み込み側で一致させておけば、簡単に保存した値の再利用ができます。(もっとも、このような使い方がリソースの正しい使い方かという問題はありますが・・・)

 設定ファイルの作成場所と、保存する内容、設定を保存、及び利用するタイミングを決めてしまいましょう。
 設定ファイルの保存場所は、多くのアプリケーション等が頻繁に使用している、home/config/settingsに、BTinyEditor.cfgの名前で保存しましょう。
 保存する内容は、とりあえず、ウィンドウの大きさですので、幅と高さを保存します。幅のIDは1、高さのIDは2とします。
 保存するタイミングは、ウィンドウを閉じるときで良いでしょう。逆に利用するときは、ウィンドウを作成するときになります。

 設定ファイルのパスとIDをMainWindow.hに定義しておきます。また、初期表示位置を100,100から、20,40に変更しました。

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

#define MAINWINDOW_TITLE            "BTinyEditor" 
#define MAINWINDOW_POSITION_LEFT    20 
#define MAINWINDOW_POSITION_TOP     40 
#define MAINWINDOW_POSITION_WIDTH   600 
#define MAINWINDOW_POSITION_HEIGHT  400 
#define MAINWINDOW_WINDOWSTYLE      (B_DOCUMENT_WINDOW) 

#define RESOURCEFILEPATH            "/boot/home/config/settings/BTinyEditor.cfg"
#define R_FRAME_WIDTH               1
#define R_FRAME_HEIGHT              2

 ウィンドウを閉じるとき、つまりQuitRequested関数で設定ファイルへの保存を行います。ただし、ここでは保存用の関数を呼び出すだけで、実際の保存は新しく関数を作って行いましょう。関数の名前はSaveDataToResourceとします。

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

//--------------------------------------------------------------------
void BEditorWindow::SaveDataToResource(void)
{
    BResources res;
    BFile file(RESOURCEFILEPATH, B_READ_WRITE | B_CREATE_FILE);
    int32 wk;
    
    res.SetTo(&file);

    wk=Frame().IntegerWidth();
    res.AddResource(B_INT32_TYPE,R_FRAME_WIDTH,&wk,sizeof(wk));
    wk=Frame().IntegerHeight();
    res.AddResource(B_INT32_TYPE,R_FRAME_HEIGHT,&wk,sizeof(wk));

    res.Sync();
    file.Unset();    
}
//--------------------------------------------------------------------

 リソースファイルはBResourcesクラスで扱います。SetTo関数を使い、ファイルと結びつけます。
 リソースに情報を追加するには、AddResource関数を使用します。保存する情報の種類(int32なので、B_INT32_TYPE)、IDと保存する情報の入った領域のポインタとその領域の大きさを指定します。
 Sync関数でファイルに情報を反映します。

 SaveDataToResource関数はQuitRequested関数内で、次のようにMSG_CLOSEDメッセージを発行する前に呼び出します。

    SaveDataToResource();

    BMessage *msg_closed=new BMessage(MSG_CLOSED); 
    msg_closed->AddPointer("wnd",this); 
    be_app->PostMessage(msg_closed); 

    return true; 

 保存した値を利用してウィンドウの表示位置を調節するのは、ウィンドウを作成するBTinyEditorAppクラスのAddEditor関数で行います。
    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); 
 元々は、このようにMainWindow.hで定義した定数でウィンドウの表示位置を指定しています。これを作成する毎に位置をずらすようにします。
 最初にウィンドウを作成する場合は、定数で定義した位置にリソースファイルに保存した大きさでウィンドウを表示します。他にウィンドウが存在する場合は、直前にアクティブだったウィンドウと同じ大きさのウィンドウを、やや右下方向にずらした位置に作成するようにします。

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

//--------------------------------------------------------------------- 
BEditorWindow *BTinyEditor::AddEditor(void) 
{ 
    BEditorWindow *mainwnd; 
    BEditorWindow *targetwnd=NULL;
    BRect wndpos(MAINWINDOW_POSITION_LEFT,MAINWINDOW_POSITION_TOP, 
                 MAINWINDOW_POSITION_WIDTH+MAINWINDOW_POSITION_LEFT-1, 
                 MAINWINDOW_POSITION_HEIGHT+MAINWINDOW_POSITION_TOP-1);
    float width,height;
    
    width=wndpos.Width();
    height=wndpos.Height();
    
    if(EditorList->CountItems()>0)
        targetwnd=(BEditorWindow *)EditorList->ItemAt(
                                        EditorList->CountItems()-1);

    if(targetwnd!=NULL)
        wndpos.Set(targetwnd->Frame().left+B_V_SCROLL_BAR_WIDTH,
                   targetwnd->Frame().top+B_H_SCROLL_BAR_HEIGHT,
                   targetwnd->Frame().right+B_V_SCROLL_BAR_WIDTH,
                   targetwnd->Frame().bottom+B_H_SCROLL_BAR_HEIGHT);
    else
    {
        BResources res;
        BFile file;

        if(file.SetTo(RESOURCEFILEPATH, B_READ_ONLY)==B_OK)
        {
            size_t siz;
            int32 *wk;
            
            res.SetTo(&file);
            
            siz=sizeof(int32);
            wk=(int32 *)res.LoadResource(B_INT32_TYPE,R_FRAME_WIDTH,&siz);
            width=(float)*wk;
            
            siz=sizeof(int32);
            wk=(int32 *)res.LoadResource(B_INT32_TYPE,R_FRAME_HEIGHT,&siz);
            height=(float)*wk;

            file.Unset();    
        }
        
        wndpos.Set(wndpos.left,wndpos.top,
                   wndpos.left+width,wndpos.top+height);
    }
    
    mainwnd=new BEditorWindow(wndpos,MAINWINDOW_TITLE); 
    
    EditorList->AddItem((void *)mainwnd); 
    mainwnd->Show(); 

    return mainwnd; 
} 
//--------------------------------------------------------------------- 

 wndposに初期値(定数で定義した位置)をセットしておきます。
 既にウィンドウが存在するなら、アクティブなウィンドウを取得し、その位置を少し右下にずらした位置をwndposに設定します。ずらす量は、スクロールバーの幅(高さ)分としました。
 まだウィンドウが存在しない場合は、BResourcesクラスのLoadResource関数でウィンドウの大きさを取得しwndposに設定します。LoadResource関数が取得した値を格納している領域のポインタを返す事に注意してください。
 wndposに設定した値でBEditorWindowクラスの実体を作成してEditorListに追加すれば完成です。

 ただ、このままではたくさんのウィンドウを開いた際に、ちょっと困ったことになってしまいます。ウィンドウをずらしずらし表示していけば、そのうちに画面の外の座標にウィンドウを作成するようになってしまいます。
 これを回避するために、BScreenクラスでメインウィンドウの大きさを取得し、画面に入りきらない位置ならば、左上方向に移動して表示しなおすようにします。BScreenクラスは、コンストラクタの引数を省略して実体を作成すると、メインウィンドウを対象にします。
 それを反映したAddEditor関数は次のようになります。

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

//--------------------------------------------------------------------- 
BEditorWindow *BTinyEditorApp::AddEditor(void) 
{ 
    BEditorWindow *mainwnd; 
    BEditorWindow *targetwnd=NULL;
    BRect wndpos(MAINWINDOW_POSITION_LEFT,MAINWINDOW_POSITION_TOP, 
                 MAINWINDOW_POSITION_WIDTH+MAINWINDOW_POSITION_LEFT-1, 
                 MAINWINDOW_POSITION_HEIGHT+MAINWINDOW_POSITION_TOP-1);
    BScreen mainscreen;
    float width,height;
    
    width=wndpos.Width();
    height=wndpos.Height();
    
    if(EditorList->CountItems()>0)
        targetwnd=(BEditorWindow *)EditorList->ItemAt(
                                        EditorList->CountItems()-1);

    if(targetwnd!=NULL)
        wndpos.Set(targetwnd->Frame().left+B_V_SCROLL_BAR_WIDTH,
                   targetwnd->Frame().top+B_H_SCROLL_BAR_HEIGHT,
                   targetwnd->Frame().right+B_V_SCROLL_BAR_WIDTH,
                   targetwnd->Frame().bottom+B_H_SCROLL_BAR_HEIGHT);
    else
    {
        BResources res;
        BFile file;

        if(file.SetTo(RESOURCEFILEPATH, B_READ_ONLY)==B_OK)
        {
            size_t siz;
            int32 *wk;
            
            res.SetTo(&file);
            
            siz=sizeof(int32);
            wk=(int32 *)res.LoadResource(B_INT32_TYPE,R_FRAME_WIDTH,&siz);
            width=(float)*wk;
            
            siz=sizeof(int32);
            wk=(int32 *)res.LoadResource(B_INT32_TYPE,R_FRAME_HEIGHT,&siz);
            height=(float)*wk;

            file.Unset();    
        }
        
        wndpos.Set(wndpos.left,wndpos.top,
                   wndpos.left+width,wndpos.top+height);
    }
    
    if(wndpos.right>mainscreen.Frame().right)
        wndpos.Set(6,wndpos.top,width,wndpos.bottom);
    if(wndpos.bottom>mainscreen.Frame().bottom)
        wndpos.Set(wndpos.left,be_plain_font->Size()*2+4,
                   wndpos.right,height);

    mainwnd=new BEditorWindow(wndpos,MAINWINDOW_TITLE); 
    
    EditorList->AddItem((void *)mainwnd); 
    mainwnd->Show(); 

    return mainwnd; 
} 
//--------------------------------------------------------------------- 

 ちょっと短いですが、今回はこれで終わりです。だいぶエディタとしての格好も付いてきたような気がしますので、そろそろ次の題材を考えないとですね。
 これを利用して何かアプリケーションを作るか、それとも全然違うアプリケーションを作ろうか。結構悩みますね、これは。

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

次の項目へ

トップページへ戻る