Partager via


Exemple de Presse-papiers manuscrit

Ce programme montre comment copier et coller de l’entrée manuscrite dans une autre application. Il permet également à l’utilisateur de copier une sélection de traits et de coller le résultat dans l’objet manuscrit existant.

Les modes de Presse-papiers suivants sont disponibles :

  • Format sérialisé manuscrit (ISF)
  • Metafile
  • métafichier amélioré (EMF)
  • Bitmap
  • Texte manuscrit
  • Encre de croquis

L’encre de texte et l’encre de croquis sont deux types de contrôles d’encre utilisés respectivement comme texte ou dessin. Il est possible de coller l’ISF, l’encre de texte et l’encre de croquis dans l’encre existante.

En plus du Presse-papiers, cet exemple montre également comment sélectionner des traits avec l’outil lasso. L’utilisateur peut déplacer les traits sélectionnés et modifier ses attributs de dessin. Cette fonctionnalité est un sous-ensemble de la fonctionnalité de sélection déjà fournie par le contrôle de superposition d’encre ; il est implémenté ici à des fins d’illustration.

Les fonctionnalités suivantes sont utilisées dans cet exemple :

Cet exemple illustre le rendu de l’entrée manuscrite, la copie de cette entrée manuscrite, puis le collage de l’encre dans une autre application, telle que Microsoft Paint.

Collecte d’encre et configuration du formulaire

Tout d’abord, référencez les interfaces Tablet PC Automation, qui sont installées avec l’entité Microsoft Windows<type="reg"/> XP Tablet PC Edition Software Development Kit (SDK).

using Microsoft.Ink;

Ensuite, le formulaire déclare certaines constantes et champs qui sont notés plus loin dans cet exemple.

// 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;

Enfin, dans le gestionnaire d’événements Load du formulaire, le formulaire est initialisé, un objet InkCollector pour le formulaire est créé et le collecteur d’encre est activé.

// 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;

Gestion des événements de menu

Les gestionnaires d’événements d’élément de menu mettent principalement à jour l’état du formulaire.

La commande Effacer supprime le rectangle de sélection et supprime les traits de l’objet Ink du collecteur d’encre.

La commande Exit désactive le collecteur d’encre avant de quitter l’application.

Le menu Modifier active les commandes Couper et Copier en fonction de l’état de sélection du formulaire et active la commande Coller en fonction du contenu du Presse-papiers, déterminé à l’aide de la méthode CanPaste de l’objet Ink.

Les commandes Couper et Copier utilisent une méthode d’assistance pour copier l’entrée manuscrite dans le Presse-papiers. La commande Couper utilise une méthode d’assistance pour supprimer les traits sélectionnés.

La commande Coller vérifie d’abord la méthode CanPaste de l’objet Ink pour voir si l’objet dans le Presse-papiers peut être collé. La commande Coller calcule ensuite le coin supérieur gauche de la région de collage, convertit les coordonnées des pixels en espace d’encre et colle les traits du Presse-papiers vers le collecteur d’encre. Enfin, la zone de sélection est mise à jour.

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);
    }
}

Les commandes Sélectionner et Encre mettent à jour le mode application et les attributs de dessin par défaut, effacez la sélection actuelle, mettez à jour l’état du menu et actualisez le formulaire. D’autres gestionnaires s’appuient sur l’état de l’application pour effectuer la fonction correcte, soit lassoing, soit en déposant l’encre. En outre, la commande Select ajoute les gestionnaires d’événements NewPackets et Stroke au collecteur d’encre et la commande Ink supprime ces gestionnaires d’événements du collecteur d’encre.

Les formats disponibles dans le Presse-papiers lorsque les traits sont copiés sont répertoriés dans le menu Format et l’utilisateur sélectionne le format pour copier l’encre à partir de cette liste. Les types de formats disponibles incluent le format ISF (Ink Serialized Format), le métafichier, le métafichier amélioré et le bitmap. Les formats d’encre de croquis et d’encre de texte s’excluent mutuellement et s’appuient sur la copie de l’encre dans le Presse-papiers en tant qu’objet OLE.

Le menu Style permet à l’utilisateur de modifier les propriétés de couleur et de largeur du stylet et des traits sélectionnés.

Par exemple, la commande Rouge définit la propriété Color de la propriété DefaultDrawingAttributes du collecteur d’encre sur la couleur rouge. Étant donné que la propriété DrawingAttributes de l’objet Cursor n’a pas été définie, toute nouvelle entrée manuscrite dessinée sur le collecteur d’encre hérite de la couleur de dessin par défaut. En outre, si des traits sont actuellement sélectionnés, la propriété Color des attributs de dessin de chaque trait est également mise à jour.

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();
}

Gestion des événements de souris

Le gestionnaire d’événements MouseMove vérifie le mode d’application. Si le mode est MoveInk et qu’un bouton de souris est désactivé, le gestionnaire déplace les traits à l’aide de la méthode Move de la collection Strokes et met à jour la zone de sélection. Sinon, le gestionnaire vérifie si le rectangle de sélection contient le curseur, active la collecte d’encre en conséquence et définit également le curseur en conséquence.

Le gestionnaire d’événements MouseDown vérifie le paramètre de curseur. Si le curseur est défini sur SizeAll, le gestionnaire définit le mode d’application sur MoveInk et enregistre l’emplacement du curseur. Sinon, s’il existe une sélection actuelle, désactivez-la.

Le gestionnaire d’événements MouseUp vérifie le mode d’application. Si le mode est MoveInk, le gestionnaire définit le mode d’application en fonction de l’état vérifié de la commande Select.

L’événement NewPackets est déclenché en mode sélection lorsque le collecteur d’encre reçoit de nouvelles données de paquet. Si l’application est en mode sélection, il est nécessaire d’intercepter les nouveaux paquets et de les utiliser pour dessiner le lasso de sélection.

Les coordonnées de chaque paquet sont converties en pixels, limitées à la zone de dessin et ajoutées à la collection de points du lasso. Une méthode d’assistance est ensuite appelée pour dessiner le lasso sur le formulaire.

Gestion d’un nouveau trait

L’événement Stroke est déclenché en mode de sélection lorsqu’un nouveau trait est dessiné. Si l’application est en mode sélection, ce trait correspond au lasso et il est nécessaire de mettre à jour les informations des traits sélectionnés.

Le gestionnaire annule l’événement Stroke , vérifie la présence de plus de deux points lasso, copie la collection Points dans un tableau d’objets Point et convertit les coordonnées des points du tableau de pixels en espace d’entrée manuscrite. Ensuite, le gestionnaire utilise la méthode HitTest de l’objet Ink pour obtenir les traits sélectionnés par les points de lasso et met à jour l’état de sélection du formulaire. Enfin, le trait qui a déclenché l’événement est supprimé de la collection de traits sélectionnés, la collection lasso Points est vidée et une méthode d’assistance dessine le rectangle de sélection.

// 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);

Copie d’encre dans le Presse-papiers

La méthode d’assistance CopyInkToClipboard crée une valeur InkClipboardFormats, vérifie l’état du menu Format pour mettre à jour les formats à placer dans le Presse-papiers et utilise la méthode Presse-papiersCopy de l’objet Ink pour copier les traits dans le Presse-papiers.

// 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");
}

Mise à jour d’une sélection

La méthode d’assistance SetSelection met à jour le fichier selectedStrokes et si la collection a la valeur NULL ou EMPTY, le rectangle de sélection est défini sur le rectangle vide. Si la collection Strokes sélectionnée n’est pas vide, la méthode SetSelection effectue les étapes suivantes :

  • Détermine le rectangle englobant à l’aide de la méthode GetBoundingBox de la collection de traits
  • Convertit les coordonnées du rectangle de l’espace d’entrée manuscrite en pixels
  • Gonfle le rectangle pour fournir un espace visuel entre celui-ci et les traits sélectionnés
  • Crée des handles de sélection pour la zone de sélection actuelle

Enfin, la méthode SetSelection définit la visibilité des poignées de sélection et définit la propriété AutoRedraw du collecteur d’encre sur FALSE, si les traits sont sélectionnés.

// 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();

Dessin du Lasso

Le lasso est dessiné sous la forme d’une série de points ouverts qui suivent le chemin du trait de lasso et une ligne de connecteur pointillée entre les deux extrémités. L’événement NewPackets est déclenché au fur et à mesure que le lasso est dessiné, et le gestionnaire d’événements transmet les informations de trait à la méthode DrawLasso.

La méthode d’assistance DrawLasso supprime d’abord l’ancienne ligne de connecteur, puis itère sur les points du trait. Ensuite, DrawLasso calcule où placer les points le long du trait et les dessine. Enfin, il dessine une nouvelle ligne de connecteur.

Fermeture du formulaire

La méthode Dispose du formulaire supprime l’objet InkCollector , myInkCollector.