Tworzenie kontrolki wejściowej pisma odręcznego
Możesz utworzyć niestandardową kontrolkę, która dynamicznie i statycznie renderuje atrament. Oznacza to renderowanie atramentu w miarę rysowania przez użytkownika pociągnięcia, powodując, że atrament wydaje się "płynąć" z pióra tabletu, oraz wyświetlanie atramentu po dodaniu go do kontrolki za pomocą pióra tabletu, wklejenia ze Schowka lub załadowania z pliku. Aby dynamicznie renderować atrament, kontrolka musi używać DynamicRenderer. Aby statycznie renderować atrament, należy zastąpić metody zdarzeń rysika (OnStylusDown, OnStylusMovei OnStylusUp), aby zbierać dane StylusPoint, tworzyć pociągnięcia i dodawać je do InkPresenter (co renderuje atrament na kontrolce).
Ten temat zawiera następujące podsekcje:
Jak: Zbierać dane punktowe rysika i tworzyć pociągnięcia tuszowe
Jak: włączyć kontrolkę, aby akceptowała dane wejściowe z myszy
Jak zbierać dane punktowe rysika i tworzyć pociągnięcia pisma odręcznego
Aby utworzyć kontrolkę, która zbiera pociągnięcia pisma odręcznego i zarządza nimi, wykonaj następujące czynności:
Utwórz klasę na podstawie Control lub jednej z klas pochodzących z Control, takich jak Label.
using System; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Input.StylusPlugIns; using System.Windows.Controls; using System.Windows;
class InkControl : Label {
}
Dodaj InkPresenter do klasy i ustaw właściwość Content na nową InkPresenter.
InkPresenter ip; public InkControl() { // Add an InkPresenter for drawing. ip = new InkPresenter(); this.Content = ip; }
Dołącz RootVisual z DynamicRenderer do InkPresenter, wywołując metodę AttachVisuals, i dodaj DynamicRenderer do kolekcji StylusPlugIns. Dzięki temu InkPresenter wyświetla atrament, gdy dane punktu rysika są zbierane przez kontrolę.
public InkControl() {
// Add a dynamic renderer that // draws ink as it "flows" from the stylus. dr = new DynamicRenderer(); ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes); this.StylusPlugIns.Add(dr); }
Zastąpij metodę OnStylusDown. W tej metodzie przechwyć rysik przy użyciu wywołania Capture. Przechwytując rysik, kontrolka będzie nadal otrzymywać zdarzenia StylusMove i StylusUp, nawet jeśli rysik opuści granice kontrolki. Nie jest to ściśle obowiązkowe, ale prawie zawsze pożądane dla dobrego środowiska użytkownika. Utwórz nowy StylusPointCollection, aby zebrać dane StylusPoint. Na koniec dodaj początkowy zestaw danych StylusPoint do StylusPointCollection.
protected override void OnStylusDown(StylusDownEventArgs e) { // Capture the stylus so all stylus input is routed to this control. Stylus.Capture(this); // Allocate memory for the StylusPointsCollection and // add the StylusPoints that have come in so far. stylusPoints = new StylusPointCollection(); StylusPointCollection eventPoints = e.GetStylusPoints(this, stylusPoints.Description); stylusPoints.Add(eventPoints); }
Zastąpij metodę OnStylusMove i dodaj dane StylusPoint do utworzonego wcześniej obiektu StylusPointCollection.
protected override void OnStylusMove(StylusEventArgs e) { if (stylusPoints == null) { return; } // Add the StylusPoints that have come in since the // last call to OnStylusMove. StylusPointCollection newStylusPoints = e.GetStylusPoints(this, stylusPoints.Description); stylusPoints.Add(newStylusPoints); }
Zastąpij metodę OnStylusUp i utwórz nową Stroke przy użyciu danych StylusPointCollection. Dodaj nowy Stroke, który stworzyłeś, do kolekcji StrokesInkPresenter i zwolnij przechwytywanie rysikiem.
protected override void OnStylusUp(StylusEventArgs e) { if (stylusPoints == null) { return; } // Add the StylusPoints that have come in since the // last call to OnStylusMove. StylusPointCollection newStylusPoints = e.GetStylusPoints(this, stylusPoints.Description); stylusPoints.Add(newStylusPoints); // Create a new stroke from all the StylusPoints since OnStylusDown. Stroke stroke = new Stroke(stylusPoints); // Add the new stroke to the Strokes collection of the InkPresenter. ip.Strokes.Add(stroke); // Clear the StylusPointsCollection. stylusPoints = null; // Release stylus capture. Stylus.Capture(null); }
Jak włączyć kontrolkę, aby przyjmowała dane z myszy
Jeśli dodasz poprzednią kontrolkę do aplikacji, uruchom ją i użyjesz myszy jako urządzenia wejściowego, zauważysz, że pociągnięcia nie są utrwalane. Aby utrwalić pociągnięcia, gdy mysz jest używana jako urządzenie wejściowe, wykonaj następujące czynności:
Zastąpij OnMouseLeftButtonDown i utwórz nowy StylusPointCollection Pobierz pozycję myszy, gdy wystąpiło zdarzenie, i utwórz StylusPoint przy użyciu danych punktów i dodaj StylusPoint do StylusPointCollection.
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); // If a stylus generated this event, return. if (e.StylusDevice != null) { return; } // Start collecting the points. stylusPoints = new StylusPointCollection(); Point pt = e.GetPosition(this); stylusPoints.Add(new StylusPoint(pt.X, pt.Y)); }
Zastąpij metodę OnMouseMove. Uzyskaj pozycję myszy, gdy wystąpiło zdarzenie, i utwórz StylusPoint przy użyciu danych punktów. Dodaj StylusPoint do utworzonego wcześniej obiektu StylusPointCollection.
protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // If a stylus generated this event, return. if (e.StylusDevice != null) { return; } // Don't collect points unless the left mouse button // is down. if (e.LeftButton == MouseButtonState.Released || stylusPoints == null) { return; } Point pt = e.GetPosition(this); stylusPoints.Add(new StylusPoint(pt.X, pt.Y)); }
Zastąpij metodę OnMouseLeftButtonUp. Utwórz nowy Stroke przy użyciu danych StylusPointCollection i dodaj nowy Stroke utworzony do kolekcji StrokesInkPresenter.
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); // If a stylus generated this event, return. if (e.StylusDevice != null) { return; } if (stylusPoints == null) { return; } Point pt = e.GetPosition(this); stylusPoints.Add(new StylusPoint(pt.X, pt.Y)); // Create a stroke and add it to the InkPresenter. Stroke stroke = new Stroke(stylusPoints); stroke.DrawingAttributes = dr.DrawingAttributes; ip.Strokes.Add(stroke); stylusPoints = null; }
Składanie wszystkiego razem
Poniższy przykład to niestandardowa kontrolka, która zbiera atrament, gdy użytkownik używa myszy lub pióra.
using System;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Controls;
using System.Windows;
// A control for managing ink input
class InkControl : Label
{
InkPresenter ip;
DynamicRenderer dr;
// The StylusPointsCollection that gathers points
// before Stroke from is created.
StylusPointCollection stylusPoints = null;
public InkControl()
{
// Add an InkPresenter for drawing.
ip = new InkPresenter();
this.Content = ip;
// Add a dynamic renderer that
// draws ink as it "flows" from the stylus.
dr = new DynamicRenderer();
ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
this.StylusPlugIns.Add(dr);
}
static InkControl()
{
// Allow ink to be drawn only within the bounds of the control.
Type owner = typeof(InkControl);
ClipToBoundsProperty.OverrideMetadata(owner,
new FrameworkPropertyMetadata(true));
}
protected override void OnStylusDown(StylusDownEventArgs e)
{
// Capture the stylus so all stylus input is routed to this control.
Stylus.Capture(this);
// Allocate memory for the StylusPointsCollection and
// add the StylusPoints that have come in so far.
stylusPoints = new StylusPointCollection();
StylusPointCollection eventPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(eventPoints);
}
protected override void OnStylusMove(StylusEventArgs e)
{
if (stylusPoints == null)
{
return;
}
// Add the StylusPoints that have come in since the
// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);
}
protected override void OnStylusUp(StylusEventArgs e)
{
if (stylusPoints == null)
{
return;
}
// Add the StylusPoints that have come in since the
// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);
// Create a new stroke from all the StylusPoints since OnStylusDown.
Stroke stroke = new Stroke(stylusPoints);
// Add the new stroke to the Strokes collection of the InkPresenter.
ip.Strokes.Add(stroke);
// Clear the StylusPointsCollection.
stylusPoints = null;
// Release stylus capture.
Stylus.Capture(null);
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// If a stylus generated this event, return.
if (e.StylusDevice != null)
{
return;
}
// Start collecting the points.
stylusPoints = new StylusPointCollection();
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// If a stylus generated this event, return.
if (e.StylusDevice != null)
{
return;
}
// Don't collect points unless the left mouse button
// is down.
if (e.LeftButton == MouseButtonState.Released ||
stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
// If a stylus generated this event, return.
if (e.StylusDevice != null)
{
return;
}
if (stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
// Create a stroke and add it to the InkPresenter.
Stroke stroke = new Stroke(stylusPoints);
stroke.DrawingAttributes = dr.DrawingAttributes;
ip.Strokes.Add(stroke);
stylusPoints = null;
}
}
Korzystanie z dodatkowych wtyczek i DynamicRenderers
Podobnie jak InkCanvas, twoja kontrolka niestandardowa może mieć niestandardowe obiekty StylusPlugIn i dodatkowe obiekty DynamicRenderer. Dodaj je do kolekcji StylusPlugIns. Kolejność obiektów StylusPlugIn w StylusPlugInCollection wpływa na wygląd tuszu podczas renderowania. Załóżmy, że masz DynamicRenderer o nazwie dynamicRenderer
i niestandardową StylusPlugIn o nazwie translatePlugin
, która przesuwa atrament z pióra tabletu. Jeśli translatePlugin
jest pierwszym StylusPlugIn w StylusPlugInCollection, a dynamicRenderer
jest drugim, atrament, który "przepływy" zostanie przesunięty, gdy użytkownik przenosi pióro. Jeśli dynamicRenderer
jest pierwszy, a translatePlugin
jest drugi, atrament nie zostanie przesunięty, dopóki użytkownik nie podniesie pióra.
Konkluzja
Możesz utworzyć kontrolkę, która zbiera i renderuje pisma odręcznego, przesłaniając metody zdarzeń rysika. Tworząc własną kontrolkę, wyprowadzając własne klasy StylusPlugIn i wstawiając je do StylusPlugInCollection, możesz zaimplementować praktycznie dowolne zachowanie, które można sobie wyobrazić za pomocą cyfrowego atramentu. Masz dostęp do danych StylusPoint w miarę ich generowania, co umożliwia dostosowanie danych wejściowych Stylus i odpowiednie renderowanie ich na ekranie stosownie do potrzeb aplikacji. Ponieważ masz niskopoziomowy dostęp do danych StylusPoint, możesz zaimplementować zbieranie danych i przedstawiać je z optymalną wydajnością dla twojej aplikacji.
Zobacz też
- zaawansowana obsługa tuszu
- Dostęp do danych wejściowych pióra i manipulacja nimi
.NET Desktop feedback