Esempio di Appunti penna
Questo programma illustra come copiare e incollare input penna in un'altra applicazione. Consente inoltre all'utente di copiare una selezione di tratti e incollare il risultato nell'oggetto input penna esistente.
Sono disponibili le modalità degli Appunti seguenti:
- Formato serializzato penna (ISF)
- Metafile
- Enhanced Metafile (EMF)
- Bitmap
- Input penna testo
- Penna di disegno
L'input penna e l'input penna di testo sono due tipi di controlli input penna usati rispettivamente come testo o disegno. È possibile incollare l'input penna, l'input penna di testo e l'input penna esistente.
Oltre agli Appunti, questo esempio illustra anche come selezionare i tratti con lo strumento lasso. L'utente può spostare i tratti selezionati e modificare gli attributi di disegno. Questa funzionalità è un subset della funzionalità di selezione già fornita dal controllo sovrimpressione input penna; viene implementato qui per scopi illustrativi.
In questo esempio vengono usate le funzionalità seguenti:
- Oggetto InkCollector .
- Supporto degli Appunti penna.
- Uso del lasso con il metodo Microsoft.Ink.Ink.HitTest .
Questo esempio illustra il rendering dell'input penna, copiando l'input penna e incollando l'input penna in un'altra applicazione, ad esempio Microsoft Paint.
Raccolta input penna e configurazione del modulo
Prima di tutto, fare riferimento alle interfacce di Automazione pc Tablet, installate con il tipo di entità microsoft Windows<="reg"/> XP Tablet PC Edition Software Development Kit (SDK).
using Microsoft.Ink;
Successivamente, il modulo dichiara alcune costanti e campi annotati più avanti in questo esempio.
// 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;
Infine, nel gestore eventi Load del modulo, il modulo viene inizializzato, viene creato un oggetto InkCollector per il modulo e l'agente di raccolta input penna è abilitato.
// 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;
Gestione degli eventi del menu
I gestori eventi della voce di menu aggiornano principalmente lo stato del modulo.
Il comando Clear rimuove il rettangolo di selezione ed elimina i tratti dall'oggetto Ink dell'agente di raccolta input penna .
Il comando Exit disabilita l'agente di raccolta input penna prima di uscire dall'applicazione.
Il menu Modifica abilita i comandi Taglia e Copia in base allo stato di selezione del modulo e abilita il comando Incolla in base al contenuto degli Appunti, determinato usando il metodo CanPaste dell'oggetto Ink.
I comandi Taglia e Copia usano entrambi un metodo helper per copiare l'input penna negli Appunti. Il comando Cut usa un metodo helper per eliminare i tratti selezionati.
Il comando Incolla controlla prima il metodo CanPaste dell'oggetto Ink per verificare se l'oggetto negli Appunti può essere incollato. Il comando Incolla calcola quindi l'angolo superiore sinistro per l'area incolla, converte le coordinate da pixel a spazio penna e incolla i tratti dagli Appunti all'agente di raccolta input penna. Infine, la casella di selezione viene aggiornata.
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);
}
}
I comandi Select e Ink aggiornano la modalità applicazione e gli attributi predefiniti del disegno, deselezionano la selezione corrente, aggiornano lo stato del menu e aggiornano il modulo. Altri gestori si basano sullo stato dell'applicazione per eseguire la funzione corretta, lassoing o la disposizione dell'input penna. Inoltre, il comando Select aggiunge i gestori eventi NewPackets e Stroke all'agente di raccolta input penna e il comando Ink rimuove questi gestori eventi dall'agente di raccolta input penna.
I formati disponibili negli Appunti quando i tratti vengono copiati vengono elencati nel menu Formato e l'utente seleziona il formato per la copia dell'input penna da questo elenco. I tipi di formati disponibili includono Ink Serialized Format (ISF), metafile, metafile avanzato e bitmap. I formati di input penna e penna dello schizzo si escludono a vicenda e si basano sull'input penna copiato negli Appunti come oggetto OLE.
Il menu Stile consente all'utente di modificare le proprietà di colore e larghezza della penna e di qualsiasi tratto selezionato.
Ad esempio, il comando Red imposta la proprietà Color della proprietà DefaultDrawingAttributes dell'agente di raccolta input penna sul colore rosso. Poiché la proprietà DrawingAttributes dell'oggetto Cursor non è stata impostata, qualsiasi nuovo input penna disegnato nell'agente di raccolta input penna eredita al colore di disegno predefinito. Inoltre, se sono attualmente selezionati i tratti, anche la proprietà Color degli attributi di disegno di ogni tratto viene aggiornata.
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();
}
Gestione degli eventi del mouse
Il gestore eventi MouseMove controlla la modalità applicazione. Se la modalità è MoveInk e un pulsante del mouse è inattivo, il gestore sposta i tratti usando il metodo Move dell'insieme Strokes e aggiorna la casella di selezione. In caso contrario, il gestore verifica se il rettangolo di selezione contiene il cursore, abilita la raccolta penna di conseguenza e imposta il cursore di conseguenza.
Il gestore eventi MouseDown controlla l'impostazione del cursore. Se il cursore è impostato su SizeAll, il gestore imposta la modalità applicazione su MoveInk e registra la posizione del cursore. In caso contrario, se è presente una selezione corrente, deselezionarla.
Il gestore eventi MouseUp controlla la modalità applicazione. Se la modalità è MoveInk, il gestore imposta la modalità applicazione in base allo stato controllato del comando Select.
L'evento NewPackets viene generato in modalità di selezione quando l'agente di raccolta input penna riceve nuovi dati di pacchetto. Se l'applicazione è in modalità di selezione, è necessario intercettare i nuovi pacchetti e usarli per disegnare il lasso di selezione.
La coordinata di ogni pacchetto viene convertita in pixel, vincolata all'area di disegno e aggiunta alla raccolta di punti del lasso. Viene quindi chiamato un metodo helper per disegnare il lasso sul modulo.
Gestione di un nuovo tratto
L'evento Stroke viene generato nella modalità di selezione quando viene disegnato un nuovo tratto. Se l'applicazione è in modalità di selezione, questo tratto corrisponde al lasso ed è necessario aggiornare le informazioni dei tratti selezionati.
Il gestore annulla l'evento Stroke , verifica la presenza di più di due punti lasso, copia l'insieme Points in una matrice di oggetti Point e converte le coordinate dei punti nella matrice da pixel a spazio penna. Il gestore usa quindi il metodo HitTest dell'oggetto Ink per ottenere i tratti selezionati dai punti lasso e aggiorna lo stato di selezione del modulo. Infine, il tratto che ha generato l'evento viene rimosso dalla raccolta di tratti selezionati, l'insieme lasso Points viene svuotato e un metodo helper disegna il rettangolo di selezione.
// 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);
Copia dell'input penna negli Appunti
Il metodo helper CopyInkToClipboard crea un valore InkClipboardFormats, controlla lo stato del menu Format per aggiornare i formati da inserire negli Appunti e usa il metodo Clipboard dell'oggetto Ink per copiare i tratti negli Appunti.
// 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");
}
Aggiornamento di una selezione
Il metodo helper SetSelection aggiorna il file selectedStrokes e se la raccolta è NULLo EMPTY, il rettangolo di selezione è impostato sul rettangolo vuoto. Se l'insieme Strokes selezionato non è vuoto, il metodo SetSelection esegue la procedura seguente:
- Determina il rettangolo di selezione usando il metodo GetBoundingBox dell'insieme tratti
- Converte le coordinate del rettangolo dallo spazio penna ai pixel
- Gonfia il rettangolo per fornire uno spazio visivo tra di esso e i tratti selezionati
- Crea handle di selezione per la casella di selezione corrente
Infine, il metodo SetSelection imposta la visibilità degli handle di selezione e imposta la proprietà AutoRedraw dell'agente di raccolta input penna su FALSE, se vengono selezionati i tratti.
// 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();
Disegno del lasso
Il lasso viene disegnato come una serie di punti aperti che seguono il percorso del tratto lasso e una linea del connettore tratteggiata tra le due estremità. L'evento NewPackets viene generato quando viene disegnato il lasso e il gestore eventi passa le informazioni sul tratto al metodo DrawLasso.
Il metodo helper DrawLasso rimuove prima la riga del connettore precedente e quindi esegue l'iterazione dei punti nel tratto. DrawLasso calcola quindi dove posizionare i punti lungo il tratto e disegnarli. Infine, disegna una nuova linea del connettore.
Chiusura del modulo
Il metodo Dispose del modulo elimina l'oggetto InkCollector , myInkCollector.