次の方法で共有


インク クリップボード サンプル

このプログラムでは、インクをコピーして別のアプリケーションに貼り付ける方法を示します。 また、ユーザーは選択したストロークをコピーし、結果を既存のインク オブジェクトに貼り付けることもできます。

次のクリップボード モードを使用できます。

  • インクシリアル化形式 (ISF)
  • Metafile
  • 拡張メタファイル (EMF)
  • Bitmap
  • テキスト インク
  • スケッチ インク

テキスト インクとスケッチ インクは、それぞれテキストまたは描画として使用される 2 種類のインク コントロールです。 ISF、テキスト インク、スケッチ インクを既存のインクに貼り付けることができます。

このサンプルでは、クリップボードに加えて、なげなわツールを使用してストロークを選択する方法も示します。 ユーザーは、選択したストロークを移動し、描画属性を変更できます。 この機能は、インク オーバーレイ コントロールによって既に提供されている選択機能のサブセットです。これは説明のためにここに実装されています。

このサンプルでは、次の機能を使用します。

このサンプルでは、インクのレンダリング、そのインクのコピー、Microsoft ペイントなどの別のアプリケーションへのインクの貼り付けについて説明します。

インクの収集とフォームの設定

まず、Microsoft Windows<エンティティ型 ="reg"/> XP Tablet PC Edition Software Development Kit (SDK) と共にインストールされているタブレット PC オートメーション インターフェイスを参照します。

using Microsoft.Ink;

次に、このサンプルの後半で説明する定数とフィールドをフォームで宣言します。

// Declare constant for the size of the border around selected strokes
private const int SelectedInkWidthIncrease = 105;

// Declare constant for the size of a lasso point
private const int DotSize = 6;

// Declare constant for the spacing between lasso points
private const int DotSpacing = 7;

// Declare constant for the selection rectangle padding
private const int SelectionRectBuffer = 8;

// Declare constant for the lasso hit test percent (specifies how much
// of the stoke must fall within the lasso in order to be selected).
private const float LassoPercent = 50;
...
// Declare the InkCollector object
private InkCollector myInkCollector = null;

// The points in the selection lasso
private ArrayList lassoPoints = null;

// The array of rectangle selection handles
private PictureBox[] selectionHandles;

// The rectangle that bounds the selected strokes
private Rectangle selectionRect = Rectangle.Empty;

// The strokes that have been selected by the lasso
private Strokes selectedStrokes = null;
...
// Declare the colors used in the selection lasso
private Color dotEdgeColor = Color.White;
private Color dotColor = SystemColors.Highlight;
private Color connectorColor = Color.Black;

// Declare the pens used to draw the selection lasso
private Pen connectorPen = null;
private Pen dotEdgePen = null;
private Pen dotPen = null;

最後に、フォームの Load イベント ハンドラーで、フォームが初期化され、フォームの InkCollector オブジェクトが作成され、インク コレクターが有効になります。

// Create an ink collector and assign it to this form's window
myInkCollector = new InkCollector(this.Handle);

// Turn the ink collector on
myInkCollector.Enabled = true;

メニュー イベントの処理

メニュー項目イベント ハンドラーは、主にフォームの状態を更新します。

Clear コマンドは、選択四角形を削除し、インク コレクターの Ink オブジェクトからストロークを削除します。

Exit コマンドは、アプリケーションを終了する前にインク コレクターを無効にします。

[編集] メニューでは、フォームの選択状態に基づいて [切り取り] コマンドと [コピー] コマンドを有効にし、 Ink オブジェクトの CanPaste メソッドを使用して決定されたクリップボードの内容に基づいて [貼り付け] コマンドを有効にします。

切り取りとコピーの両方のコマンドは、ヘルパー メソッドを使用してインクをクリップボードにコピーします。 [切り取り] コマンドでは、ヘルパー メソッドを使用して、選択したストロークを削除します。

Paste コマンドは、まず Ink オブジェクトの CanPaste メソッドをチェックして、クリップボード上のオブジェクトを貼り付けることができるかどうかを確認します。 次に、[貼り付け] コマンドは、貼り付け領域の左上隅を計算し、座標をピクセルからインク空間に変換し、クリップボードからインク コレクターにストロークを貼り付けます。 最後に、選択ボックスが更新されます。

if (myInkCollector.Ink.CanPaste())
{
   // Compute the location where the ink should be pasted;
    // this location should be shifted from the origin
    // to account for the width of the selection rectangle's handle.
    Point offset = new Point(leftTopHandle.Width+1,leftTopHandle.Height+1);
    using (Graphics g = CreateGraphics())
    {
        myInkCollector.Renderer.PixelToInkSpace(g, ref offset);
    }
    // Use Ink API to paste the clipboard data into the Ink
    Strokes pastedStrokes = myInkCollector.Ink.ClipboardPaste(offset);

    // If the contents of the clipboard were a valid format 
    // (Ink Serialized Format or Embeddable OLE Object) and at
    // least one stroke was pasted into the ink, use a helper 
    // method to update the stroke selection.  Otherwise,
    // the result is null and this paste becomes a no-op.  
    if (null != pastedStrokes)
    {
        SetSelection(pastedStrokes);
    }
}

Select コマンドと Ink コマンドは、アプリケーション モードと既定の描画属性を更新し、現在の選択をクリアし、メニューの状態を更新して、フォームを更新します。 他のハンドラーは、アプリケーションの状態に依存して、なげなわやインクの敷設など、正しい機能を実行します。 さらに、Select コマンドは 、NewPackets イベント ハンドラーと Stroke イベント ハンドラーをインク コレクターに追加し、Ink コマンドによってこれらのイベント ハンドラーがインク コレクターから削除されます。

ストロークのコピー時にクリップボードで使用できる形式が [書式] メニューに表示され、ユーザーはこの一覧からインクをコピーする形式を選択します。 使用できる形式の種類には、Ink Serialized Format (ISF)、メタファイル、拡張メタファイル、ビットマップなどがあります。 スケッチ インクとテキスト インクの形式は相互に排他的であり、OLE オブジェクトとしてクリップボードにコピーされるインクに依存します。

[スタイル] メニューを使用すると、ペンと選択したストロークの色と幅のプロパティを変更できます。

たとえば、赤コマンドは、インク コレクターの DefaultDrawingAttributes プロパティの Color プロパティを赤の色に設定します。 Cursor オブジェクトの DrawingAttributes プロパティが設定されていないため、インク コレクターに描画された新しいインクは、既定の描画色に継承されます。 また、ストロークが現在選択されている場合は、各ストロークの描画属性 Color プロパティも更新されます。

private void SetColor(Color newColor)
{
    myInkCollector.DefaultDrawingAttributes.Color = newColor;

    // In addition to updating the ink collector, also update
    // the drawing attributes of all selected strokes.
    if (HasSelection())
    {
        foreach (Stroke s in selectedStrokes)
        {
            s.DrawingAttributes.Color = newColor;
        }
    }

    Refresh();
}

マウス イベントの処理

MouseMove イベント ハンドラーは、アプリケーション モードを確認します。 モードが MoveInk でマウス ボタンがダウンしている場合、ハンドラーは Strokes コレクションの Move メソッドを使用してストロークを移動し、選択ボックスを更新します。 それ以外の場合、ハンドラーは選択四角形にカーソルが含まれているかどうかを確認し、それに応じてインクコレクションを有効にし、それに応じてカーソルを設定します。

MouseDown イベント ハンドラーは、カーソルの設定を確認します。 カーソルが SizeAll に設定されている場合、ハンドラーはアプリケーション モードを MoveInk に設定し、カーソルの位置を記録します。 それ以外の場合は、現在の選択範囲がある場合はクリアします。

MouseUp イベント ハンドラーは、アプリケーション モードを確認します。 モードが MoveInk の場合、ハンドラーは Select コマンドのチェック状態に基づいてアプリケーション モードを設定します。

NewPackets イベントは、インク コレクターが新しいパケット データを受信すると、選択モードで発生します。 アプリケーションが選択モードの場合は、新しいパケットをインターセプトし、それらを使用して選択なげなわを描画する必要があります。

各パケットの座標はピクセルに変換され、描画領域に制限され、なげなわのポイントのコレクションに追加されます。 その後、ヘルパー メソッドが呼び出され、フォームになげなわが描画されます。

新しいストロークの処理

Stroke イベントは、新しいストロークが描画されるときに選択モードで発生します。 アプリケーションが選択モードの場合、このストロークはなげなわに対応し、選択したストロークの情報を更新する必要があります。

ハンドラーは Stroke イベントをキャンセルし、2 つ以上のなげなわポイントをチェックし、Points コレクションを Point オブジェクトの配列にコピーし、配列内のポイントの座標をピクセルからインク空間に変換します。 次に、ハンドラーは Ink オブジェクトの HitTest メソッドを使用して、なげなわポイントによって選択されたストロークを取得し、フォームの選択状態を更新します。 最後に、イベントを発生させたストロークが選択したストロークのコレクションから削除され、なげなわ Points コレクションが空になり、ヘルパー メソッドによって選択四角形が描画されます。

// This stroke corresponds to the lasso - 
// cancel it so that it is not added into the ink
e.Cancel = true;  

Strokes hitStrokes = null;

// If there are enough lasso points, perform a hit test
// to determine which strokes were selected. 
if (lassoPoints.Count > 2)
{

    // Convert the lasso points from pixels to ink space
    Point[] inkLassoPoints = (Point[])lassoPoints.ToArray(typeof(Point));
    using (Graphics g = CreateGraphics())
    {
        myInkCollector.Renderer.PixelToInkSpace(g, ref inkLassoPoints);
    }
    // Perform a hit test on this ink collector's ink to
    // determine which points were selected by the lasso stroke.
    //
    // Note that there is a slight inefficiency here since the
    // lasso stroke is part of the ink and, therefore, part of the
    // hit test - even though we don't need it.   It would have 
    // been more efficient to remove the stroke from the ink before 
    // calling HitTest.  However, it is not good practice to modify 
    // the stroke inside of its own event handler.
    hitStrokes = myInkCollector.Ink.HitTest(inkLassoPoints, LassoPercent);
    hitStrokes.Remove(e.Stroke);
}

// Reset the lasso points
lassoPoints.Clear();
lastDrawnLassoDot = Point.Empty;

// Use helper method to set the selection
SetSelection(hitStrokes);

クリップボードへのインクのコピー

CopyInkToClipboard ヘルパー メソッドは InkClipboardFormats 値を作成し、[書式] メニューの状態をチェックしてクリップボードに配置する書式を更新し、 Ink オブジェクトの ClipboardCopy メソッドを使用してストロークをクリップボードにコピーします。

// Declare the ink clipboard formats to put on the clipboard
InkClipboardFormats formats = new InkClipboardFormats();

// Use selected format menu items to set the clipboard 
// formats
...

// If at least one format was selected, invoke the Ink
// API's ClipboardCopy method.  Note that selectedStrokes
// could be null, but that this is ok - if selectedStrokes
// is null, all of the ink is copied.
if (formats != InkClipboardFormats.None)
{
    myInkCollector.Ink.ClipboardCopy(selectedStrokes,formats,clipboardModes);
}
else
{
    MessageBox.Show("No clipboard formats selected");
}

選択範囲の更新

SetSelection ヘルパー メソッドは、ファイルされた selectedStrokes を更新し、コレクションが NULL または EMPTY の場合、選択範囲の四角形は空の四角形に設定されます。 選択した Strokes コレクションが空でない場合、SetSelection メソッドは次の手順を実行します。

  • strokes コレクションの GetBoundingBox メソッドを使用して、外接する四角形を決定します。
  • 四角形の座標をインク空間からピクセルに変換します
  • 四角形を拡張して、その間と選択したストロークの間に視覚的なスペースを提供します
  • 現在の選択ボックスの選択ハンドルを作成します

最後に、SetSelection メソッドは、ストロークが選択されている場合、選択ハンドルの可視性を設定し、インク コレクターの AutoRedraw プロパティを FALSE に設定します。

// Tracks whether the rectangle that bounds the selected
// strokes should be displayed
bool isSelectionVisible = false;

// Update the selected strokes collection
selectedStrokes = strokes;

// If no strokes are selected, set the selection rectangle
// to empty
if (!HasSelection())
{
    selectionRect = Rectangle.Empty;
}
    // Otherwise, at least one stroke is selected and it is necessary
    // to display the selection rectangle.
else
{
    isSelectionVisible = true;

    // Retrieve the bounding box of the strokes
    selectionRect = selectedStrokes.GetBoundingBox();
    using (Graphics g = CreateGraphics())
    {
        InkSpaceToPixel(g, ref selectionRect);
    }

    // Pad the selection rectangle so that the selected ink 
    // doesn't overlap with the selection rectangle's handles.
    selectionRect.Inflate(SelectionRectBuffer, SelectionRectBuffer);

    // compute the center of the rectangle that bounds the 
    // selected strokes
    int xAvg = (selectionRect.Right+selectionRect.Left)/2;
    int yAvg = (selectionRect.Top+selectionRect.Bottom)/2;

    // Draw the resize handles
    // top left
    SetLocation(selectionHandles[0],selectionRect.Left, selectionRect.Top);
    // top
    SetLocation(selectionHandles[1],xAvg, selectionRect.Top);
    // top right 
    SetLocation(selectionHandles[2],selectionRect.Right, selectionRect.Top);

    // left 
    SetLocation(selectionHandles[3],selectionRect.Left, yAvg);
    // right
    SetLocation(selectionHandles[4],selectionRect.Right, yAvg);

    // bottom left
    SetLocation(selectionHandles[5],selectionRect.Left, selectionRect.Bottom);
    // bottom
    SetLocation(selectionHandles[6],xAvg, selectionRect.Bottom);
    // bottom right
    SetLocation(selectionHandles[7],selectionRect.Right, selectionRect.Bottom);
}

// Set the visibility of each selection handle in the 
// selection rectangle.  If there is no selection, all 
// handles should be hidden.  Otherwise, all handles should
// be visible.
foreach(PictureBox pb in selectionHandles)
{
    pb.Visible = isSelectionVisible;
}

// Turn off autoredrawing if there is a selection - otherwise,
// the selected ink is not displayed as selected.
myInkCollector.AutoRedraw = !isSelectionVisible;

// Since the selection has changed, repaint the screen.
Refresh();

なげなわの描画

なげなわは、なげなわストロークのパスと、両端の間の破線のコネクタ線に続く一連の開いたドットとして描画されます。 NewPackets イベントはなげなわが描画されるときに発生し、イベント ハンドラーはストローク情報を DrawLasso メソッドに渡します。

DrawLasso ヘルパー メソッドは、最初に古いコネクタ線を削除してから、ストローク内のポイントを反復処理します。 次に、DrawLasso はストロークに沿ってドットを配置する場所を計算し、描画します。 最後に、新しいコネクタ線を描画します。

フォームを閉じる

フォームの Dispose メソッドは、 InkCollector オブジェクト myInkCollector を破棄します。