Compartilhar via


Exemplo da coleção de tinta RealTimeStylus

Este aplicativo demonstra a coleta e a renderização de tinta ao usar a classe RealTimeStylus .

O Projeto InkCollection

Este exemplo consiste em uma única solução que contém um projeto, InkCollection. O aplicativo define o InkCollection namespace que contém uma única classe, também chamada InkCollection. A classe herda da classe Form e implementa a interface IStylusAsyncPlugin .

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

A Classe InkCollection define um conjunto de constantes privadas usadas para especificar várias espessuras de tinta. A classe também declara instâncias privadas da classe RealTimeStylus, myRealTimeStylus, a classe DynamicRenderer e myDynamicRenderera classe myRendererRenderer . O DynamicRenderer renderiza o Traço que está sendo coletado no momento. O objeto Renderer, myRenderer, renderiza objetos Stroke que já foram coletados.

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

private RealTimeStylus myRealTimeStylus;

private DynamicRenderer myDynamicRenderer;
private Renderer myRenderer;

A classe também declara um objeto Hashtable , myPackets, que é usado para armazenar dados de pacotes que estão sendo coletados por um ou mais objetos Cursor . Os valores de ID do objeto Stylus são usados como a chave de tabela de hash para identificar exclusivamente os dados de pacote coletados para um determinado objeto Cursor.

Uma instância privada do objeto Ink , myInk, armazena objetos Stroke coletados por myRealTimeStylus.

private Hashtable myPackets;
        
private Ink myInk;

O evento de carregamento de formulário

No manipulador de eventos Load para o formulário, myDynamicRenderer é instanciado usando o DynamicRenderer que assume um controle como argumento e myRenderer é construído com um construtor sem argumento.

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

Preste atenção ao comentário que segue a instanciação dos renderizadores, pois myDynamicRenderer usa os valores padrão para DrawingAttributes ao renderizar a tinta. Esse é o comportamento padrão. No entanto, se você quiser fornecer a tinta renderizada por myDynamicRenderer uma aparência diferente da tinta renderizada por myRenderer, poderá alterar a propriedade DrawingAttributes em myDynamicRenderer. Para fazer isso, remova o comentário das linhas a seguir antes de compilar e executar o aplicativo.

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

Em seguida, o aplicativo cria o objeto RealTimeStylus que é usado para receber notificações de caneta e adiciona o objeto DynamicRenderer à fila de notificação de plug-in síncrona. Especificamente, myRealTimeStylus adiciona myDynamicRenderer à propriedade SyncPluginCollection .

    myRealTimeStylus = new RealTimeStylus(this, true);

    myRealTimeStylus.SyncPluginCollection.Add(myDynamicRenderer);

Em seguida, o formulário é adicionado à fila de notificação de plug-in assíncrona. Especificamente, InkCollection é adicionado à propriedade AsyncPluginCollection . Por fim, myRealTimeStylus e myDynamicRenderer estão habilitados, e myPackets e myInk são instanciados.

    myRealTimeStylus.AsyncPluginCollection.Add(this);

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

Além de conectar os manipuladores de menu para alterar a cor e o tamanho da tinta, mais um breve bloco de código é necessário antes de implementar a interface. O exemplo deve manipular o evento Paint do formulário. No manipulador de eventos, o aplicativo deve ser atualizado myDynamicRenderer porque é possível que um objeto Stroke esteja sendo coletado no momento em que o evento Paint ocorre. Nesse caso, a parte do objeto Stroke que já foi coletada precisa ser redesenhada. O Renderizador estático é usado para desenhar novamente objetos Stroke que já foram coletados. Esses traços estão no objeto Ink porque são colocados lá quando desenhados, conforme mostrado na próxima seção.

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

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

Implementando a interface IStylusAsyncPlugin

O aplicativo de exemplo define os tipos de notificações que tem interesse em receber na implementação da propriedade DataInterest . Portanto, a propriedade DataInterest define quais notificações o objeto RealTimeStylus encaminha para o formulário. Para este exemplo, a propriedade DataInterest define o interesse nas notificações StylusDown, Packets, StylusUp e Error por meio da enumeração DataInterestMask .

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

A notificação StylusDown ocorre quando a caneta toca na superfície do digitalizador. Quando isso acontece, o exemplo aloca uma matriz usada para armazenar os dados do pacote para o objeto Stylus . O StylusDownData do método StylusDown é adicionado à matriz e a matriz é inserida no hashtable usando a propriedade Id do objeto Stylus como uma chave.

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

    collectedPackets.AddRange(data.GetData());

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

A notificação pacotes ocorre quando a caneta se move na superfície do digitalizador. Quando isso ocorre, o aplicativo adiciona o novo StylusDownData à matriz de pacotes para o objeto Stylus . Ele faz isso usando a propriedade Id do objeto Stylus como a chave para recuperar a matriz de pacotes para a caneta do hash. Em seguida, os novos dados de pacote são inseridos na matriz recuperada.

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

A notificação stylusUp ocorre quando a caneta deixa a superfície do digitalizador. Quando essa notificação ocorre, o exemplo recupera a matriz de pacotes para esse objeto Stylus do hashtable-removendo-o do hashtable, pois ele não é mais necessário, adiciona os novos dados de pacote e usa a matriz de dados de pacote para criar um novo objeto 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;
    } 
}

Para obter um exemplo que mostra um uso mais robusto da classe RealTimeStylus , incluindo o uso da criação de plug-in personalizado, consulte Exemplo de plug-in RealTimeStylus.

Microsoft.Ink.Renderer

Microsoft.StylusInput.DynamicRenderer

Microsoft.StylusInput.RealTimeStylus

Microsoft.StylusInput.IStylusAsyncPlugin

Acessando e manipulando entrada de caneta