Ejemplo de divisor de entrada de lápiz
Este ejemplo se basa en el ejemplo de colección de lápiz. Muestra cómo usar el objeto Divider para analizar la entrada de lápiz.
Para obtener información conceptual detallada sobre Divider, vea El objeto Divisor.
Cuando se actualiza el formulario, el ejemplo dibuja un rectángulo delimitador alrededor de cada unidad analizada, dividida en palabras, líneas, párrafos y dibujos. Además de usar diferentes colores, estos rectángulos se amplían por diferentes cantidades para asegurarse de que ninguno de los rectángulos está oculto por otros. En la tabla siguiente se especifica el color y la ampliación de cada unidad analizada.
unidad analizada | Color | Ampliación de píxeles |
---|---|---|
Word |
Verde |
1 |
Línea |
Fucsia |
3 |
Paragraph |
Azul |
5 |
Dibujo |
Rojo |
1 |
Configurar el formulario
Cuando se carga el formulario, se crea un objeto Divider . Se crea un objeto InkOverlay y se asocia a un panel del formulario. A continuación, los controladores de eventos se adjuntan al objeto InkOverlay para realizar un seguimiento cuando se agregan y eliminan trazos. A continuación, si los reconocedores están disponibles, se asigna un objeto RecognizerContext para el reconocedor predeterminado al divisor. A continuación, se establece la propiedad LineHeight del objeto Divider y la colección Strokes del objeto InkOverlay se asigna al Divisor. Por último, el objeto InkOverlay está habilitado.
// 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;
La colección Strokes del objeto Divider debe mantenerse sincronizada con la colección Strokes del objeto InkOverlay (a la que se tiene acceso a través de la propiedad Ink del objeto InkOverlay). Para asegurarse de que esto sucede, el controlador de eventos Stroke del objeto InkOverlay se escribe de la siguiente manera. Tenga en cuenta que el controlador de eventos comprueba primero si editingMode está establecido en Ink para filtrar los trazos del borrador. Si el usuario ha solicitado análisis de diseño automático, la aplicación llama al método DivideInk del formulario y actualiza el área de dibujo.
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();
}
}
}
Dividir la entrada de lápiz
Cuando el usuario hace clic en Dividir en el menú Archivo, se llama al método Divide en el objeto Divider . Se usa el reconocedor predeterminado, si está disponible.
DivisionResult divResult = myInkDivider.Divide();
El objeto DivisionResult resultante, al que hace referencia la variable divResult
, se pasa a una función de utilidad, getUnitBBBoxes()
. La función de utilidad devuelve una matriz de rectángulos para cualquier tipo de división solicitado: segmentos, líneas, párrafos o dibujos.
myWordBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Segment, 1);
myLineBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Line, 3);
myParagraphBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Paragraph, 5);
myDrawingBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Drawing, 1);
Por último, el panel de formulario se fuerza a volver a dibujar para que aparezcan los rectángulos delimitadores.
DrawArea.Refresh();
Resultados del análisis de entrada de lápiz
En la función de utilidad, el objeto DivisionResult se consulta para sus resultados mediante el método ResultByType , según el tipo de división solicitado por el autor de la llamada. El método ResultByType devuelve una colección DivisionUnits . Cada DivisionUnit de la colección representa un dibujo, un único segmento de reconocimiento de escritura a mano, una línea de escritura a mano o un bloque de escritura a mano, dependiendo de lo especificado cuando se llamó a la función de utilidad.
DivisionUnits units = divResult.ResultByType(divType);
Si hay al menos una DivisionUnit, se crea una matriz de rectángulos que contiene un rectángulo delimitador por unidad. (Los rectángulos se inflan mediante cantidades diferentes para cada tipo de unidad, que se mantienen en la variable de inflado, para evitar la superposición).
// 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
}
Volver a dibujar el formulario
Cuando se fuerza el nuevo dibujo anterior, el código siguiente se ejecuta para pintar los cuadros de límite de cada DivisiónUnit en el formulario alrededor de la entrada de lápiz.
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);
}
}
Cerrar el formulario
El método Dispose del formulario elimina los objetos InkOverlay, Divider, RecognizerContext y la colección Strokes usada en el ejemplo.