前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

10.9. レスポンダの描画

10.9.1. 描画領域

レスポンダには以下の 3 種類の領域があります。

  • ベース領域 : レスポンダ全体の領域
  • コンテント領域 : 文字や図形を描画するための領域
  • フレーム領域 : ベース領域からコンテント領域を除いた領域

図 10.51. タイトルウィンドウ (SFRTitleWindow) の例

タイトルウィンドウ (SFRTitleWindow) の例

表 10.14. 領域を取得/設定する関数

関数名 解説
GetBaseBound 所有関係の親レスポンダのコンテント座標系でベース領域を取得します。
GetBaseWorld ベース領域を取得します。
SetBaseBound 所有関係の親レスポンダのコンテント座標系でベース領域を設定します。
GetContentBound ベース領域の座標系でコンテント領域を取得します。
GetContentWorld コンテント領域を取得します。
SetContentBound ベース領域の座標系でコンテント領域を設定します。
GetFrameMargin ベース領域とコンテント領域の間のマージンを取得します。
SetFrameMargin ベース領域とコンテント領域の間のマージンを設定します。

図 10.52. ボタン (SFRButtonControl) の例

ボタン (SFRButtonControl) の例
[Note] 注意
ボタンの場合、コンテント領域とベース領域は同じになります。

例 10.61. 上図のレスポンダの作成

SFRTitleWindowPtr window1 = new SFRTitleWindow(SFRApplication::GetInstance(),
                                               SFXRectangle(10, 15, 180, 200),
                                               "Window 1");
SFRButtonControlPtr button1 = new SFRButtonControl(window1,
                                                   SFXRectangle(15, 30, 120, 40),
                                                   "button1");

例 10.62. 領域取得関数の使い方

SFXRectangle rectangle;
SFXMargin margin;

// window1 の領域の取得方法
rectangle = window1->GetBaseBound();    // ベース領域を親レスポンダの座標系で取得する
// rectangle は ( 10 , 15 , 180 , 200 ) になる( 左端 10、上端 15、幅 180、高さ 200) 

rectangle = window1->GetBaseWorld();    // ベース領域を取得する
// rectangle は ( 0 , 0 , 180 , 200 ) になる

rectangle = window1->GetContentBound(); // コンテント領域をベース領域の座標系で取得する
// rectangle は ( 2 , 25 , 175 , 172 ) になる

rectangle = window1->GetContentWorld(); //コンテント領域を取得する
// rectangle は (0 , 0 , 175 , 172 ) になる

margin = window1->GetFrameMargin();     // フレーム領域をマージンとして取得する
// margin は ( 2 , 25 , 3 , 3 ) になる
// (左マージン 2、上マージン 25、右マージン 3、下マージン 3)

// button1 の領域の取得方法
rectangle = button1->GetBaseBound();    // ベース領域を親(window1)の座標系で取得する
// rectangle は ( 15 , 30 , 120 , 40 ) になる

rectangle = button1->GetBaseWorld();    // ベース領域を取得する
// rectangle は ( 0 , 0 , 120 , 40 ) になる

rectangle = button1->GetContentBound(); // コンテント領域をベース領域の座標系で取得する
// rectangle は ( 0 , 0 , 120 , 40 ) になる
// button にはフレーム領域が無いので、GetBaseWorld と結果が同じになる

rectangle = button1->GetContentWorld(); //コンテント領域を取得する
// rectangle は ( 0 , 0 , 120 , 40 ) になる

margin = button1->GetFrameMargin();     // フレーム領域をマージンとして取得する
// margin は ( 0 , 0 , 0 , 0 ) になる

SFXMargin は上下左右の余白 (マージン) を表します。

10.9.2. スクロール

仮想領域はコンテント領域よりも大きなオブジェクトを描画するときに使います。

図 10.53. 仮想領域

仮想領域

例 10.63. ウィンドウ内の仮想領域の描画

// window1 は SFRTitleWindow 型のポインタで、上図のウィンドウを指す

// ウィンドウのコンテント領域よりも大きな領域を仮想領域として設定する
window1->SetVirtualBound(SFXRectangle(0, 0, 200, 1000));

例 10.64. window1 の描画ハンドラ

// 仮想領域全体を白く塗りつぶす
graphics->FillRectangle(GetVirtualWorld(), SFXRGBColor(0xFF, 0xFF, 0xFF, 0x00));

SInt32 fontHeight = graphics->GetFontHeight();  // フォントの高さを取得する

SInt32 i;
for (i = 0; i < 14; ++i) {
    SFXRectangle rect(0, i * 30, 150, fontHeight); // 矩形

    // 「i 行目」という文字列を表示
    SFXAnsiString str = SFXAnsiString::Format("%2d 行目", i + 1);
    graphics->DrawText(str, rect, SFXRGBColor(0x00, 0x00, 0x00, 0x00));
}

例 10.65. 仮想領域の表示範囲の変更

// window1 の仮想領域をスクロールさせる。引数でスクロール量の指定
window1->Scroll(SFXSize(0, 40));

仮想領域の表示範囲を変えるには Scroll 関数を用います。

図 10.54. ベース領域、コンテント領域、フレーム領域、仮想領域

ベース領域、コンテント領域、フレーム領域、仮想領域

図 10.55. ウィンドウの場合の領域

ウィンドウの場合の領域

10.9.3. 再描画

レスポンダを再描画する方法は以下の通りです。

  1. レスポンダのベース領域を再描画するには、InvalidateBase 関数を使用してその領域を再描画領域として登録します。
  2. レスポンダのコンテント領域を再描画するには、InvalidateContent 関数を使用してその領域を再描画領域として登録します。
  3. レスポンダのコンテント領域内矩形領域を再描画するには、InvalidateContent 関数を使用してその領域を再描画領域として登録します。

再描画領域を登録すると、イベントループの出口で再描画領域として登録されたレスポンダの描画ハンドラが自動的に起動され、再描画領域は再描画されます。

例 10.66. 再描画

// responder のコンテント領域を再描画する
responder->InvalidateContent();

// responder のベース領域を再描画する
responder->InvalidateBase();

// responder のコンテント領域の一部分を再描画する ( 矩形領域で指定する )
responder->InvalidateContent(SFXRectangle(10, 20, 40, 40));

10.9.4. 強制描画

タイマーやネットワークなど処理のコールバック関数で Invalidate 関数を呼び出した場合は、 再描画イベントをアプリケーションクラスのインスタンスに送信して強制再描画する必要があります。

例 10.67. 強制再描画

// 登録した領域の強制再描画
SFRApplication::GetInstance()->Invoke(SFXEvent(SREVT_RESPONDER_RENDER, 
                                               SRP16_RENDER_INVOKE, 
                                               false));

// 登録した領域に無関係に全レスポンダの強制再描画
SFRApplication::GetInstance()->Invoke(SFXEvent(SREVT_RESPONDER_RENDER, 
                                               SRP16_RENDER_INVOKE, 
                                               true));
[Warning] 警告

再描画イベントは必ずアプリケーションクラスのインスタンスに送信します。

強制描画は時間がかかる処理なのでできるだけ避けます。

10.9.5. 破棄

レスポンダを破棄するには、レスポンダに SREVT_RESPONDER_TERMINATE イベントを送信します。

コンストラクタ内でレスポンダ作成中にエラーが発生した場合は、delete 演算子を使用してレスポンダを破棄します。

例 10.68. レスポンダの破棄

SFRWindowPtr window;

if ((window = new SFRTitleWindow(this, SFXRectangle(0, 0, 100, 100), "Sample")) != null) {
  if (window->static_catch() == SFERR_NO_ERROR) {
    window->Invoke(SFXEvent(SREVT_RESPONDER_TERMINATE, 
                            SRP16_TERMINATE_INVOKE, 
                            true));
  }
  else {
    delete window;
  }
}

10.9.6. リファレンス値

レスポンダにはリファレンス値 ( VoidPtr 型 ) を設定できます。

例 10.69. ボタンのラベル付け

SFRButtonControlPtr button;
SInt32 i;

// 番号 ( リファレンス値 ) を設定して 10 個のボタンを作成する
for (i = 0; i < 10; ++i) {
    button = new SFRButtonControl(this, SFXRectangle(0, i * 30, 20, 20), ");

    // ボタンに識別のための番号をつける
    button->SetReference(reinterpret_cast<VoidPtr>(i));
}

...

// 番号 ( リファレンス値 ) 番号を取得する
SInt32 number = reinterpret_cast<SInt32>(button->GetReference());