Udostępnij przez


Przykład schowka atramentowego

Ten program pokazuje, jak skopiować i wkleić atrament do innej aplikacji. Umożliwia również użytkownikowi skopiowanie zaznaczenia pociągnięć i wklejenie wyniku do istniejącego obiektu atramentu.

Dostępne są następujące tryby schowka:

  • Format serializacji atramentu (ISF)
  • Metafile
  • Rozszerzony metaplik (EMF)
  • Bitmapa
  • Atrament tekstowy
  • Atrament do szkicowania

Atrament tekstowy i atrament szkicowy to dwa typy kontrolek atramentu używane odpowiednio jako tekst lub rysunek. Można wkleić elementy ISF, atrament tekstowy i atrament szkicowy do istniejącego atramentu.

Oprócz schowka ten przykład ilustruje również sposób wybierania pociągnięć za pomocą narzędzia lasso. Użytkownik może przenosić wybrane pociągnięcia i modyfikować ich atrybuty rysunku. Ta funkcja jest podzbiorem funkcji wyboru, które są już udostępniane przez kontrolkę nakładki atramentu; jest ona implementowana w tym miejscu w celach ilustracyjnych.

W tym przykładzie są używane następujące funkcje:

W tym przykładzie pokazano renderowanie tuszu, kopiowanie tego tuszu, a następnie wklejanie go do innej aplikacji, takiej jak Microsoft Paint.

Zbieranie tuszu i konfigurowanie formularza

Najpierw należy odwołać się do interfejsów automatyzacji tabletów PC, które są instalowane razem z Microsoft Windows<entity="reg"/> XP Tablet PC Edition Software Development Kit (SDK).

using Microsoft.Ink;

Następnie formularz deklaruje niektóre stałe i pola, które zostały zanotowane w dalszej części tego przykładu.

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

Na koniec w procedurze obsługi zdarzenia ładowania formularz jest inicjowany, tworzony jest obiekt InkCollector formularza, a kolektor pisma odręcznego jest włączony.

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

Obsługa zdarzeń menu

Programy obsługi zdarzeń elementu menu aktualizują przede wszystkim stan formularza.

Polecenie Clear likwiduje prostokąt zaznaczenia i usuwa ślady pociągnięć z obiektu atramentu z modułu zbierającego atrament.

Polecenie Zakończ wyłącza moduł zbierający atrament przed zamknięciem aplikacji.

Menu Edycja włącza polecenia Wycinanie i kopiowanie na podstawie stanu zaznaczenia formularza i włącza polecenie Wklej na podstawie zawartości schowka określonego przy użyciu metody ink obiektu CanPaste.

Polecenia Wytnij i Kopiuj używają metody pomocniczej do kopiowania atramentu cyfrowego do schowka. Polecenie Cut używa metody pomocniczej do usuwania zaznaczonych pociągnięć.

Polecenie Wklej najpierw sprawdza metodę CanPaste obiektu Ink, aby sprawdzić, czy obiekt w schowku można wkleić. Następnie polecenie Wklej oblicza lewy górny róg regionu wklejania, konwertuje współrzędne z pikseli na przestrzeń pisma i wkleja pociągnięcia ze schowka do kolektora pisma. Na koniec pole wyboru zostanie zaktualizowane.

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

Polecenia Select i Ink aktualizują tryb aplikacji oraz domyślne atrybuty rysunku, wyczyść bieżące zaznaczenie, zaktualizuj stan menu i odśwież formularz. Inne obsługi polegają na stanie aplikacji w celu wykonania poprawnej funkcji, takiej jak zawiązywanie liny lub nakładanie tuszu. Ponadto polecenie Select dodaje procedury obsługi zdarzeń NewPackets i Stroke do modułu zbierającego pisma odręcznego, a polecenie Ink usuwa te procedury obsługi zdarzeń z modułu zbierającego pisma odręcznego.

Formaty dostępne w Schowku podczas kopiowania odręcznych pociągnięć są wyświetlane w menu Format, a użytkownik wybiera format kopiowania atramentu z tej listy. Dostępne typy formatów to Ink Serialized Format (ISF), metaplik, rozszerzony metaplik i mapa bitowa. Formaty atramentu szkicu i atramentu tekstu wzajemnie się wykluczają i polegają na tym, że atrament jest kopiowany do schowka jako obiekt OLE.

Menu Styl umożliwia użytkownikowi zmianę właściwości koloru i szerokości pióra oraz wszystkich zaznaczonych pociągnięć.

Na przykład polecenie Red ustawia właściwość Color modułu zbierającego pisma odręcznego DefaultDrawingAttributes właściwości kolor czerwony. Ponieważ właściwość DrawingAttributes obiektu Kursor nie została ustawiona, każdy nowy atrament rysowany przez kolektor atramentu dziedziczy domyślny kolor rysowania. Ponadto, jeśli jakiekolwiek pociągnięcia są aktualnie zaznaczone, właściwość Kolor atrybutów rysunku każdego pociągnięcia również zostanie zaktualizowana.

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

Obsługa zdarzeń myszy

Program obsługi zdarzeń MouseMove sprawdza tryb aplikacji. Jeśli tryb to MoveInk i przycisk myszy jest wciśnięty, program obsługi przenosi pociągnięcia za pomocą metody Move kolekcji Strokes i aktualizuje pole zaznaczenia. W przeciwnym razie program obsługi sprawdza, czy prostokąt zaznaczenia zawiera kursor, włącza odpowiednio zbieranie pisma odręcznego i ustawia kursor.

Program obsługi zdarzeń MouseDown sprawdza ustawienie kursora. Jeśli kursor jest ustawiony na SizeAll, program obsługi ustawia tryb aplikacji na MoveInk i rejestruje lokalizację kursora. W przeciwnym razie, jeśli istnieje bieżące zaznaczenie, wyczyść je.

Program obsługi zdarzeń MouseUp sprawdza tryb aplikacji. Jeśli tryb to MoveInk, program obsługi ustawia tryb aplikacji na podstawie stanu zaznaczonego polecenia Select.

Zdarzenie NewPackets jest wywoływane w trybie wyboru, gdy moduł zbierający tusz odbiera nowe dane o pakietach. Jeśli aplikacja jest w trybie zaznaczania, należy przechwycić nowe pakiety i użyć ich do rysowania lassa zaznaczenia.

Współrzędna każdego pakietu jest konwertowana na piksele, a następnie ograniczana do obszaru rysunku i dodawana do kolekcji punktów lasso. Następnie wywoływana jest metoda pomocnicza, aby narysować lasso w formularzu.

Postępowanie po nowym udarze

Zdarzenie jest wywoływane w trybie zaznaczenia, gdy zostanie narysowana nowa kreska. Jeśli aplikacja jest w trybie wyboru, to pociągnięcie odpowiada lasso i konieczne jest zaktualizowanie informacji o wybranych pociągnięciach.

Procedura obsługi anuluje zdarzenie pociągnięcia, sprawdza, czy jest więcej niż dwa punkty lasso, kopiuje kolekcję Punktów do tablicy obiektów Point i konwertuje współrzędne punktów w tablicy z pikseli na przestrzeń atramentu. Następnie program obsługi używa metody HitTest obiektu Ink w celu pobrania pociągnięć wybranych przez punkty lasso i aktualizuje stan zaznaczenia formularza. Na koniec pociągnięcie, które wywołało zdarzenie, jest usuwane z kolekcji wybranych pociągnięć, kolekcja Lasso Points jest opróżniona, a metoda pomocnicza rysuje prostokąt zaznaczenia.

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

Kopiowanie Ink do Schowka

Funkcja pomocnicza CopyInkToClipboard tworzy wartość InkClipboardFormats, sprawdza stan menu Format, aby zaktualizować formaty do umieszczenia w schowku, i używa metody ClipboardCopy obiektu Ink, aby skopiować pociągnięcia do schowka.

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

Aktualizowanie zaznaczenia

Metoda pomocnicza SetSelection aktualizuje pole selectedStrokes, a jeśli kolekcja jest NULL lub EMPTY, prostokąt zaznaczenia jest ustawiony na pusty prostokąt. Jeśli wybrana kolekcja Strokes nie jest pusta, metoda SetSelection wykonuje następujące czynności:

  • Określa prostokąt ograniczenia przy użyciu metody GetBoundingBox zbioru pociągnięć
  • Konwertuje współrzędne prostokąta z przestrzeni tuszu na piksele
  • Powiększa prostokąt, aby stworzyć pewną przestrzeń wizualną wokół niego i wybranych pociągnięć.
  • Tworzy uchwyty wyboru dla bieżącego pola wyboru

Na koniec metoda SetSelection ustawia widoczność uchwytów zaznaczenia i ustawia właściwość AutoRedraw kolektora tuszu na FALSE, jeśli wybrano pociągnięcia.

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

Używanie narzędzia lasso

Lasso jest rysowane jako seria otwartych kropek, które podążają ścieżką pociągnięcia lassa, oraz przerywanej linii łączącej między dwoma końcami. Zdarzenie NewPackets jest wywoływane w trakcie rysowania lassa, a obsługujący zdarzenie przekazuje informacje o kresce do metody DrawLasso.

Metoda pomocnicza DrawLasso najpierw usuwa starą linię łącznika, a następnie iteruje po punktach w śladzie. Następnie DrawLasso oblicza, gdzie umieścić kropki wzdłuż pociągnięcia i rysuje je. Na koniec rysuje nową linię łącznika.

Zamykanie formularza

Metoda Dispose formularza usuwa obiekt InkCollector, myInkCollector.