此範例是以 Ink 集合範例為基礎。 它示範如何使用 分隔器 物件來分析手寫輸入。
更新表單時,範例會在每個分析單位周圍繪製周框矩形,並分成文字、線條、段落和繪圖。 除了使用不同的色彩,這些矩形也會以不同的數量放大,以確保其他矩形不會遮蔽任何矩形。 下表指定每個分析單位的色彩和放大。
| 分析單位 | 顏色 | 像素放大 |
|---|---|---|
| 詞 |
綠 |
1 |
| 線 |
品紅 |
3 |
| 段 |
藍 |
5 |
| 繪圖 |
紅 |
1 |
設定表單
當窗體載入時,會建立 Divider 物件。 會建立 InkOverlay 物件,並且將其與表單上的面板相關聯。 然後事件處理程式會附加至 InkOverlay 物件,以追蹤何時新增和刪除筆劃。 然後,如果辨識器可供使用,則會將預設辨識器的 RecognizerContext 物件指派給除法器。 然後會設定 Divider 物件的 LineHeight 屬性,並將 InkOverlay 物件的 Strokes 集合指派給 Divider。 最後,已啟用 InkOverlay 物件。
// Create the ink overlay and associate it with the form
myInkOverlay = new Microsoft.Ink.InkOverlay(DrawArea.Handle);
// Set the erasing mode to stroke erase.
myInkOverlay.EraserMode = InkOverlayEraserMode.StrokeErase;
// Hook event handler for the Stroke event to myInkOverlay_Stroke.
// This is necessary since the application needs to pass the strokes
// to the ink divider.
myInkOverlay.Stroke += new InkCollectorStrokeEventHandler(myInkOverlay_Stroke);
// Hook the event handler for StrokeDeleting event to myInkOverlay_StrokeDeleting.
// This is necessary as the application needs to remove the strokes from
// ink divider object as well.
myInkOverlay.StrokesDeleting += new InkOverlayStrokesDeletingEventHandler(myInkOverlay_StrokeDeleting);
// Hook the event handler for StrokeDeleted event to myInkOverlay_StrokeDeleted.
// This is necessary to update the layout analysis result when automatic layout analysis
// option is selected.
myInkOverlay.StrokesDeleted += new InkOverlayStrokesDeletedEventHandler(myInkOverlay_StrokeDeleted);
// Create the ink divider object
myInkDivider = new Divider();
// Add a default recognizer context to the divider object
// without adding the recognizer context, the divider would
// not use a recognizer to do its word segmentation and would
// have less accurate results.
// Adding the recognizer context slows down the call to
// myInkDivider.Divide though.
// It is possible that there is no recognizer installed on the
// machine for this language. In that case the divider does
// not use a recognizer to improve its accuracy.
// Get the default recognizer if any
try
{
Recognizers recognizers = new Recognizers();
myInkDivider.RecognizerContext = recognizers.GetDefaultRecognizer().CreateRecognizerContext();
}
catch (InvalidOperationException)
{
//We are in the case where no default recognizers can be found
}
// The LineHeight property helps the InkDivider distinguish between
// drawing and handwriting. The value should be the expected height
// of the user's handwriting in ink space units (0.01mm).
// Here we set the LineHeight to 840, which is about 1/3 of an inch.
myInkDivider.LineHeight = 840;
// Assign ink overlay's strokes collection to the ink divider
// This strokes collection is updated in the event handler
myInkDivider.Strokes = myInkOverlay.Ink.Strokes;
// Enable ink collection
myInkOverlay.Enabled = true;
除法器 物件的 Strokes 集合必須與 InkOverlay 物件的 Strokes 集合保持同步(透過 InkOverlay 物件的 Ink 屬性存取)。 為了確保發生這種情況,InkOverlay 物件的 Stroke 事件處理程式會寫入如下。 請注意,事件處理程式會先測試以查看 EditingMode 是否設定為 Ink 來篩選掉橡皮擦筆劃。 如果使用者已要求自動配置分析,則應用程式會呼叫表單的 DivideInk 方法,並重新整理繪圖區域。
private void myInkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e )
{
// Filter out the eraser stroke.
if(InkOverlayEditingMode.Ink == myInkOverlay.EditingMode)
{
// Add the new stroke to the ink divider's strokes collection
myInkDivider.Strokes.Add(e.Stroke);
if(miAutomaticLayoutAnalysis.Checked)
{
// Call DivideInk
DivideInk();
// Repaint the screen to reflect the change
DrawArea.Refresh();
}
}
}
分墨
當使用者單擊 [檔案] 功能表上的 [除法] 時,在 Divider 物件上會呼叫 Divide 方法。 如果有的話,會使用預設辨識器。
DivisionResult divResult = myInkDivider.Divide();
變數 divResult所參考的結果 DivisionResult 物件會傳遞至公用程式函式,getUnitBBBoxes()。 公用程式函式會針對要求的任何除法類型傳回矩形陣列:區段、線條、段落或繪圖。
myWordBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Segment, 1);
myLineBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Line, 3);
myParagraphBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Paragraph, 5);
myDrawingBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Drawing, 1);
最後,表單面板會被強制重新繪製,以便讓邊界矩形出現。
DrawArea.Refresh();
筆跡分析結果
在公用程式函式中,會根據呼叫端所要求的除法類型,使用 ResultByType 方法,查詢 DivisionResult 對象的結果。 ResultByType 方法會傳回 DivisionUnits 集合。 集合中的每個 DivisionUnit 代表繪圖、手寫的單一辨識區段、手寫線條或手寫區塊,視呼叫公用程式函式時所指定的內容而定。
DivisionUnits units = divResult.ResultByType(divType);
如果有至少一個 DivisionUnit,則會建立一個矩形陣列,其中每個單位包含一個包圍矩形。 (矩形根據每種單位類型在充氣變數中儲存的不同數值進行擴大,以避免重疊。
// If there is at least one unit, we construct the rectangles
if((null != units) && (0 < units.Count))
{
// We need to convert rectangles from ink units to
// pixel units. For that, we need Graphics object
// to pass to InkRenderer.InkSpaceToPixel method
using (Graphics g = DrawArea.CreateGraphics())
{
// InkSpace to Pixel Space conversion setup done here.
// Not shown for brevity.
// Iterate through the collection of division units to obtain the bounding boxes
foreach(DivisionUnit unit in units)
{
// Get the bounding box of the strokes of the division unit
divRects[i] = unit.Strokes.GetBoundingBox();
// Div unit rect Ink space to Pixel space conversion done here.
// Not shown for brevity.
// Inflate the rectangle by inflate pixels in both directions
divRects[i].Inflate(inflate, inflate);
// Increment the index
++i;
}
} // Relinquish the Graphics object
}
重新繪製表單
在上方強制重繪時,下列程式代碼會執行,為窗體上的每個 DivisionUnit 繪製筆跡周圍的周框方塊。
private void DrawArea_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// Create the Pen used to draw bounding boxes.
// First set of bounding boxes drawn here are
// the bounding boxes of paragraphs.
// These boxes are drawn with Blue pen.
Pen penBox = new Pen(Color.Blue, 2);
// First, draw the bounding boxes for Paragraphs
if(null != myParagraphBoundingBoxes)
{
// Draw bounding boxes for Paragraphs
e.Graphics.DrawRectangles(penBox, myParagraphBoundingBoxes);
}
// Next, draw the bounding boxes for Lines
if(null != myLineBoundingBoxes)
{
// Color is Magenta pen
penBox.Color = Color.Magenta;
// Draw the bounding boxes for Lines
e.Graphics.DrawRectangles(penBox, myLineBoundingBoxes);
}
// Then, draw the bounding boxes for Words
if(null != myWordBoundingBoxes)
{
// Color is Green
penBox.Color = Color.Green;
// Draw bounding boxes for Words
e.Graphics.DrawRectangles(penBox, myWordBoundingBoxes);
}
// Finally, draw the boxes for Drawings
if(null != myDrawingBoundingBoxes)
{
// Color is Red pen
penBox.Color = Color.Red;
// Draw bounding boxes for Drawings
e.Graphics.DrawRectangles(penBox, myDrawingBoundingBoxes);
}
}
關閉表單
表單的 Dispose 方法會處置 InkOverlay、Divider、RecognizerContext 物件,以及範例中使用的 Strokes 集合。