エンタープライズ:特集 2003/07/04 17:20:00 更新
C Magazine

C MAGAZINE 2002年8月号より転載
プログラムのレシピ――プログラミングの考え方・作り方 (7/13)

グラフィックエディタの製作(3)
基本機能の作成−上書き保存/画像の表示

上書き保存

 「名前をつけて保存」機能を作りましたが、今度は「上書き保存」機能を作ってみましょう。上書き保存機能とは、「ファイルを開いたときのファイル名」や「保存したときのファイル名」をそのまま使ってファイルを保存する機能です。

 これを実現するためには、次の処理が必要です。

  • ファイルを開いたときと保存したときに、ファイル名を記録しておく
  • 上書き保存のときにファイル名が記録されていたら、上書き保存する
  • ファイル名が記録されていなかったら、名前をつけて保存する
●プログラム例

 まずはビットマップ用の変数(Bitmap)と同じ要領で、ファイル名を保存するためのメンバ変数を宣言します。

AnsiString FileName;

 次はList 1とList 2に、ファイル名を記録する処理を追加します。List 1は、

FileName=OpenDialog-> FileName;

とし、List 2は、

FileName=SaveDialog-> FileName;

とします。

 あとは、List 5のように上書き保存の処理を書けばできあがりです。

List 5 上書き保存の処理(UGEditorForm.cpp)
// 上書き保存
void TGEditorForm::SaveFile() {
    if (FileName==NULL) {
        // ファイル名が不明ならば、「名前を付けて保存」にする
        SaveFileAs();
    } else {
        // ファイル名が分かっていれば、
        // そのファイル名を使って保存する
        try {
            Bitmap-> SaveToFile(FileName);
        } catch(...) {
            Application-> MessageBox(
                "ファイルが書き込めません",
                "ファイルの書き込みエラー",
                MB_OK
            );
        }
    }
}

画像の表示

 ビットマップの読み書きと同様に、ビットマップの表示もたいていのライブラリでサポートされています。Win32 APIならばBitBlt関数、VCLならばTCanvasクラスのDrawメソッドやCopyRectメソッドを使います。これらの機能を使って単にビットマップをウィンドウに描くだけです。大きな画像を表示することを考えると、スクロール表示にも対応したほうがいいですね。

 ここまで作ると、Fig. 5のように画像ファイルを読み込んで表示することができるようになります。画像の保存も可能です。

Fig5

Fig. 5 画像ファイルの読み込みと表示


●プログラム例

 C++Builderの場合には、フォームにスクロールボックス(ScrollBoxコンポーネント)を配置して、その中にペイントボックス(PaintBoxコンポーネント)を配置するのがオーソドックスな方法です。コンポーネントの配置はFig. 6を参考にしてください。

 ビットマップの表示はペイントボックスのOnPaintイベント処理で行います(List 6)。ここではTCanvasクラスのDrawメソッドを使いました。

Fig6

Fig. 6 コンポーネントの配置例(オブジェクトツリー)


List 6 ビットマップの表示(UGEditorForm.cpp)
void __fastcall TGEditorForm::PaintBoxPaint(TObject *Sender)
{
    // ペイントボックスの左上にビットマップを表示する
    TCanvas *c=PaintBox-> Canvas;
    c-> Draw(0, 0, Bitmap);
}

 またビットマップのサイズに合わせて、ペイントボックスのサイズも変更する必要があります。サイズの変更にはList 7のようなメソッドを定義して、ビットマップのサイズが変更されたときにこのメソッドを呼び出すようにします。たとえば、List 1のようなビットマップ読み込み処理のあとにこのメソッドを呼び出します。

List 7 ペイントボックスのサイズ変更(UGEditorForm.cpp)
// ビットマップのサイズが変更されたとき、
// PaintBoxのサイズを変える
void TGEditorForm::ResizePaintBox() {
    // 大きさを設定
    PaintBox-> Width=Bitmap-> Width;
    PaintBox-> Height==Bitmap-> Height;
    //========================================================= (1)
    // 再描画
    PaintBox-> Invalidate();
}

●再描画のコツ

 List 7- (1)では、ペイントボックスの再描画のためにInvalidateメソッドを使います。

 再描画に関しては、

  • Invalidate
  • Update
  • Repaint
  • Refresh

という4種類のメソッドがあります。どれも同じに見えますが、実はそれぞれ少しずつ機能が違います。

 Invalidateは「コンポーネントを再描画する必要がある」ことを宣言するメソッドです。Invalidateを呼び出したからといって、すぐに画面が更新されるわけではありません。後ほど適当なタイミングで再描画されます。

 Updateは保留していた再描画処理を実行するメソッドです。Invalidateの再描画処理は適当なタイミングで自動的に行われますが、これを強制的に行わせるのがUpdateです。

 RepaintはInvalidateとUpdateの組み合わせです。コンポーネントを再描画する必要性を宣言し、すぐに再描画を実行します。画面表示をすぐに更新したいときにはこのメソッドを使います。RefreshはRepaintと同じ意味です。

 メソッドの使い分けはケースバイケースです。厳密に使い分けなくてもたいていはうまく動きますが、描画性能をよくするにはそれなりの配慮が必要です。

 大まかな方針ですが、通常はInvalidateを使い、即座に画面更新する必要があるときだけRepaintを使うのがいいでしょう。Invalidateの場合、あとでまとめて再描画されるので余分に呼び出しても描画性能が落ちないのが長所です。Repaintを余分に呼び出すと、何度も再描画が実行されて速度低下や画面のちらつきの原因になります。

前のページ | 1 2 3 4 5 6 7 8 9 10 11 12 13 | 次のページ

[松浦健一郎(ひぐぺん工房),C MAGAZINE]

Copyright © ITmedia, Inc. All Rights Reserved.