Поделиться через


Пример коллекции рукописного ввода RealTimeStylus

Это приложение демонстрирует сбор и отрисовку рукописного ввода при использовании класса RealTimeStylus .

Проект InkCollection

Этот пример состоит из одного решения, содержащего один проект InkCollection. Приложение определяет InkCollection пространство имен, содержащее один класс, также называемый InkCollection. Класс наследуется от класса Form и реализует интерфейс IStylusAsyncPlugin .

namespace InkCollection
{
    public class InkCollection : Form, IStylusAsyncPlugin
    {
        //...
      

Класс InkCollection определяет набор частных констант, используемых для указания различной толщины рукописного фрагмента. Класс также объявляет частные экземпляры класса RealTimeStylus, myRealTimeStylus, класса myDynamicRendererDynamicRenderer и класса myRendererRenderer . DynamicRenderer отрисовывает объект Stroke, который в настоящее время собирается. Объект Renderer, , myRendererотрисовывает объекты Stroke, которые уже были собраны.

private const float ThinInkWidth = 10;
private const float MediumInkWidth = 100;
private const float ThickInkWidth = 200;

private RealTimeStylus myRealTimeStylus;

private DynamicRenderer myDynamicRenderer;
private Renderer myRenderer;

Класс также объявляет объект Hashtable , который используется для хранения данных пакетов, myPacketsсобираемых одним или несколькими объектами Cursor . Значения Id объекта Stylus используются в качестве ключа хэш-таблицы для уникальной идентификации данных пакетов, собранных для данного объекта Cursor.

Частный экземпляр объекта Ink хранит объекты Stroke, myInkсобранные myRealTimeStylus.

private Hashtable myPackets;
        
private Ink myInk;

Событие загрузки формы

В обработчике событий Load для формы создается экземпляр с помощью DynamicRenderer, myDynamicRenderer который принимает элемент управления в качестве аргумента и myRenderer создается с конструктором без аргументов.

private void InkCollection_Load(object sender, System.EventArgs e)
{
    myDynamicRenderer = new DynamicRenderer(this);
    myRenderer = new Renderer();
    // ...

Обратите внимание на комментарий, который следует за экземпляром отрисовщиков, так как myDynamicRenderer использует значения по умолчанию для DrawingAttributes при отрисовке рукописного ввода. Это стандартное поведение. Однако если вы хотите придать рукописному вводу, отрисованному с помощью myDynamicRenderer , внешний вид отличается от рукописного ввода, отображаемого с помощью myRenderer, можно изменить свойство DrawingAttributes в myDynamicRenderer. Для этого раскомментируйте следующие строки перед сборкой и запуском приложения.

    // myDynamicRenderer.DrawingAttributes.PenTip = PenTip.Rectangle;
    // myDynamicRenderer.DrawingAttributes.Height = (.5F)*MediumInkWidth;
    // myDynamicRenderer.DrawingAttributes.Transparency = 128;

Затем приложение создает объект RealTimeStylus , который используется для получения уведомлений пера, и добавляет объект DynamicRenderer в очередь уведомлений синхронного подключаемого модуля. В частности, myRealTimeStylus добавляет myDynamicRenderer в свойство SyncPluginCollection .

    myRealTimeStylus = new RealTimeStylus(this, true);

    myRealTimeStylus.SyncPluginCollection.Add(myDynamicRenderer);

Затем форма добавляется в очередь асинхронных уведомлений подключаемого модуля. В частности, InkCollection добавляется в свойство AsyncPluginCollection . Наконец, myRealTimeStylus включены и myDynamicRenderer , а также создаются экземпляры myPackets и myInk.

    myRealTimeStylus.AsyncPluginCollection.Add(this);

    myRealTimeStylus.Enabled = true;
    myDynamicRenderer.Enabled = true;  
      
    myPackets = new Hashtable();
    myInk = new Ink();
}

Помимо подключения обработчиков меню для изменения цвета и размера рукописного ввода, перед реализацией интерфейса требуется еще один краткий блок кода. Пример должен обрабатывать событие Paint формы. В обработчике событий приложение должно обновиться myDynamicRenderer , так как возможно, что объект Stroke собирается во время события Paint. В этом случае необходимо перерисовать часть уже собранного объекта Stroke. Статический отрисовщик используется для повторного рисования уже собранных объектов Stroke. Эти штрихи находятся в объекте Ink , так как они помещаются в нее при рисовании, как показано в следующем разделе.

private void InkCollection_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    myDynamicRenderer.Refresh();

    myRenderer.Draw(e.Graphics, myInk.Strokes);
} 

Реализация интерфейса IStylusAsyncPlugin

В примере приложения определяются типы уведомлений, которые оно заинтересовано в получении в реализации свойства DataInterest . Таким образом, свойство DataInterest определяет, какие уведомления объект RealTimeStylus перенаправит в форму. В этом примере свойство DataInterest определяет интерес к уведомлениям StylusDown, Packets, StylusUp и Error с помощью перечисления DataInterestMask .

public DataInterestMask DataInterest
{
    get
    {
        return DataInterestMask.StylusDown |
               DataInterestMask.Packets |
               DataInterestMask.StylusUp |
               DataInterestMask.Error;
    }
}

Уведомление StylusDown возникает, когда перо касается поверхности дигитайзера. В этом случае пример выделяет массив, который используется для хранения данных пакета для объекта Stylus . StylusDownData из метода StylusDown добавляется в массив, а массив вставляется в хэш-строку с помощью свойства Id объекта Stylus в качестве ключа.

public void StylusDown(RealTimeStylus sender, StylusDownData data)
{
    ArrayList collectedPackets = new ArrayList();

    collectedPackets.AddRange(data.GetData());

    myPackets.Add(data.Stylus.Id, collectedPackets);
}

Уведомление Пакеты возникает , когда перо перемещается по поверхности дигитайзера. В этом случае приложение добавляет новый StylusDownData в массив пакетов для объекта Stylus . Для этого используется свойство Id объекта Stylus в качестве ключа для получения массива пакетов для пера из хэш-строки. Затем новые данные пакета вставляются в полученный массив.

public void Packets(RealTimeStylus sender, PacketsData data)
{
    ((ArrayList)(myPackets[data.Stylus.Id])).AddRange(data.GetData());
}

Уведомление StylusUp возникает, когда перо покидает поверхность дигитайзера. Когда происходит это уведомление, пример извлекает массив пакетов для этого объекта Stylus из хэш-таблица, удаляя его из хэш-таблица, так как она больше не нужна, добавляет новые данные пакета и использует массив данных пакета для создания нового объекта Stroke , stroke.

public void StylusUp(RealTimeStylus sender, StylusUpData data)
{
    ArrayList collectedPackets = (ArrayList)myPackets[data.Stylus.Id];
    myPackets.Remove(data.Stylus.Id);

    collectedPackets.AddRange(data.GetData());

    int[] packets = (int[])(collectedPackets.ToArray(typeof(int)));
    TabletPropertyDescriptionCollection tabletProperties =
        myRealTimeStylus.GetTabletPropertyDescriptionCollection(data.Stylus.TabletContextId);

    Stroke stroke = myInk.CreateStroke(packets, tabletProperties);
    if (stroke != null) 
    {
         stroke.DrawingAttributes.Color = myDynamicRenderer.DrawingAttributes.Color;
         stroke.DrawingAttributes.Width = myDynamicRenderer.DrawingAttributes.Width;
    } 
}

Пример, демонстрирующий более надежное использование класса RealTimeStylus , включая создание пользовательского подключаемого модуля, см. в разделе Пример подключаемого модуля RealTimeStylus.

Microsoft.Ink.Renderer

Microsoft.StylusInput.DynamicRenderer

Microsoft.StylusInput.RealTimeStylus

Microsoft.StylusInput.IStylusAsyncPlugin

Доступ к входным данным пера и управление ими