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

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

グラフィックエディタの製作(8)
基本機能の作成−編集機能

 今度はクリップボードを使った編集機能です。マウスドラッグで範囲選択して、切り取り/コピー/貼り付けができるようにしましょう。このグラフィックエディタでは、[Shift]キー+マウスクリックで範囲選択を開始します。選択枠が表示されるので、そのままマウスをドラッグして範囲を決めます。

 範囲を決めたら、[Ctrl]+Xキーで切り取り、[Ctrl]+Cでコピーができます。クリップボードを経由するので、ほかのアプリケーションとの間でデータを交換することもできます。

 貼り付けは[Ctrl]+Vキーです。貼り付けを実行すると、貼り付け枠が表示されます(Fig. 16)。貼り付け先を決めてマウスボタンをクリックすると、貼り付けが行われます。

範囲選択

 範囲選択のポイントは選択枠の描画です。選択枠を高速に描画するには、一般にXOR(排他的論理和)描画を使います。XORを使って枠の上に同じ枠を上書きすると、枠が消えて元の背景に戻ります。これを利用すると背景を再描画しなくても済むので、枠を高速に移動することができます。

 Win32 APIの場合、XORを使って枠を描くにはDrawFocusRect関数が便利です。C++Builderの場合にも、同じ名前のDrawFocusRectメソッドを使います。

Fig16

Fig. 16 編集機能


プログラム例

 選択枠を描画するプログラムはList 16のようになります。TCanvasクラスのDrawFocusRectメソッドは、このような選択枠などを描くのに便利なメソッドです(List 16-(1))。

List 16 範囲選択枠の描画(UGEditorForm.h、UGEditorForm.cpp)
// 選択枠
TRect SelectedRect;
// 選択枠を描画(または消去)する
void TGEditorForm::ReverseIndicators() {
    TRect r;
    // 選択枠の画面上の位置を計算
    r=SelectedRect;
    r.left*=ZoomRate; r.top*=ZoomRate;
    r.right*=ZoomRate; r.bottom*=ZoomRate;
    //========================================================= (1)
    // 選択枠を描画
    c-> DrawFocusRect(r);
}

マウスイベントの処理

 マウスドラッグで範囲選択を行うためには、いくつかのマウスイベントを処理しなければなりません。VCLの主なマウスイベントには次のようなものがあります。

・OnMouseDownイベント
マウスボタンを押したときに発生
・OnMouseUpイベント
マウスボタンを離したときに発生
・OnMouseMoveイベント
マウスカーソルを移動したときに発生

 範囲選択の場合、まずOnMouseDownイベントで選択枠を表示します。次にOnMouseMoveイベントが発生するたびに選択範囲を更新し、選択枠を再描画します。OnMouseUpイベントが起きたら、範囲選択を終了します。

 範囲選択に限らず、クリックやドラッグで何かをするユーザインタフェイスを作るときには、これら3つのマウスイベントが鍵になります。先に作成した描画機能でも、これらのマウスイベントを使います。

 なおWin32 APIでも基本的な考え方は同じです。こちらの場合、WM_LBUTTONDOWNやWM_LBUTTONUPといったマウスメッセージを処理します。

切り取り、コピー、貼り付け

 範囲選択の次は、クリップボードを使った編集機能です。クリップボードとの間でデータをやりとりする機能はライブラリにあるので、これを使えば簡単です。

 Win32 APIの場合には、SetClipboardData関数とGetClipboardData関数を使います。

 C++Builderの場合には、次で説明するようにTClipboardクラスのAssignメソッドを使います。

プログラム例

 切り取り、コピー、貼り付けの処理はList 17です。このうち切り取りはList 17-(1)のように、コピーのあとに背景色で選択範囲を塗りつぶすことによって実現できます。

 コピーはList 17-(2)です。クリップボードに対してビットマップをコピーするには、TClipboardクラスのAssignメソッドを使います(List 17-(4))。Assignメソッドでは指定したビットマップを丸ごとコピーしてしまうので、選択範囲だけをコピーするためには工夫が必要です。そこでList 17-(3)のように、作業用のビットマップに選択範囲を一時的にコピーして、この作業用ビットマップをクリップボードにコピーします。

 List 17-(5)は貼り付けです。コピーのときとは逆に、TBitmapクラスのAssignメソッドを使って、クリップボードからビットマップにデータをコピーします(List 17-(6))。その後、貼り付け位置をマウス操作で選択する処理に入ります。

List 17 切り取り、コピー、貼り付け(UGEditorForm.cpp)
//============================================================= (1)
// 切り取り
void TGEditorForm::Cut() {
    // クリップボードに選択範囲をコピー
    Copy();
    // 背景色で選択範囲を塗りつぶす
    TCanvas *c=Bitmap-> Canvas;
    c-> Brush-> Color=ColorForm-> BGColor;
    c-> FillRect(r);
    RepaintBitmap(r);
}
//============================================================= (2)
// コピー
void TGEditorForm::Copy() {
    //========================================================= (3)
    // 作業用ビットマップに選択範囲をコピーの後、
    // クリップボードに転送
    TRect src, dst;
    src=SelectedRect;
    dst.left=dst.top=0;
    TempBitmap-> Width=dst.right=SelectedRect.Width();
    TempBitmap-> Height=dst.bottom=SelectedRect.Height();
    TempBitmap-> Canvas-> CopyRect(
        dst, Bitmap-> Canvas, src);
    //========================================================= (4)
    Clipboard()-> Assign(TempBitmap);
    // 範囲選択を解除
    CancelSelection();
}
//============================================================= (5)
// 貼り付け
void TGEditorForm::Paste() {
    if (Clipboard()-> HasFormat(CF_BITMAP)){
        //===================================================== (6)
        // クリップボードからビットマップを読み込む
        TempBitmap-> Assign(Clipboard());
        // ペースト位置を初期化し、貼り付けを開始
        PasteRect=TRect(0,0,0,0);
        CurrentJob=jobPaste;
    }
}

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

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

Copyright © ITmedia, Inc. All Rights Reserved.