共用方式為


筆跡剪貼簿範例

此程式示範如何將筆跡複製並貼到另一個應用程式中。 它也可讓使用者複製筆劃的選取範圍,並將結果貼到現有的筆跡物件中。

下列剪貼簿模式可供使用:

  • ISF) (筆跡序列化格式
  • 中繼檔
  • 加強型中繼檔 (EMF)
  • 點陣圖
  • 文字筆跡
  • 草圖筆跡

文字筆跡和草圖筆跡是兩種類型的筆跡控制項,分別做為文字或繪圖。 可以將 ISF、文字筆跡和草圖筆跡貼到現有的筆跡中。

除了剪貼簿之外,此範例也會說明如何使用套索工具選取筆劃。 使用者可以移動選取的筆劃,並修改其繪圖屬性。 這項功能是筆跡重迭控制項已提供之選取功能的子集;這裡實作是為了說明目的。

此範例會使用下列功能:

此範例示範轉譯筆跡、複製該筆跡,然後將筆跡貼到另一個應用程式,例如Microsoft 小畫家。

收集筆跡和設定表單

首先,參考隨 Microsoft Windows < 實體類型=「reg」/ > XP Tablet PC Edition Software Development Kit (SDK) 一起安裝的平板電腦自動化介面。

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 命令會在結束應用程式之前停用筆跡收集器。

[編輯] 功能表會根據表單的選取狀態啟用剪下和複製命令,並根據剪貼簿的內容啟用 Paste 命令,方法是使用 Ink 物件的 CanPaste 方法決定。

剪下和複製命令都會使用協助程式方法將筆跡複製到剪貼簿。 Cut 命令會使用協助程式方法來刪除選取的筆劃。

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 命令會將 NewPacketsStroke 事件處理常式新增至筆跡收集器,而 Ink 命令會從筆跡收集器中移除這些事件處理常式。

複製筆劃時,剪貼簿上可用的格式會列在 [格式] 功能表上,而使用者會選取從這份清單中複製筆跡的格式。 可用的格式類型包括筆跡序列化格式 (ISF) 、中繼檔、增強型中繼檔及點陣圖。 草圖筆跡和文字筆跡格式互斥,並依賴將筆跡複製到剪貼簿做為 OLE 物件。

[樣式] 功能表可讓使用者變更畫筆的色彩和寬度屬性,以及任何選取的筆劃。

例如,Red 命令會將筆跡收集器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 事件、檢查兩個以上的套索點、將 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 欄位,如果集合為 NullEMPTY,則選取矩形會設定為空白矩形。 如果選取的 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。