Exemplo de apagamento de impressão
Este aplicativo se baseia no exemplo de Amostra de Coleção de Tinta demonstrando a exclusão de traços de tinta. O exemplo fornece ao usuário um menu que tem quatro modos para escolher: habilitado para tinta, apagamento à borda, apagamento em interseções e apagamento de traços.
No modo habilitado para tinta, o objeto InkCollector coleta tinta, conforme mostrado no Exemplo de Coleção de Tintas.
Em um modo de apagamento, segmentos de traços de tinta existentes que o usuário toca com o cursor são apagados. Além disso, as bordas ou interseções podem ser marcadas com um círculo vermelho.
As partes mais interessantes desse exemplo estão no InkErase
manipulador de eventos do OnPaint
formulário e nas funções de apagamento que são chamadas do manipulador de eventos do OnMouseMove
formulário.
Circulando as bordas e interseções
O manipulador de eventos do OnPaint
formulário primeiro pinta os traços e, dependendo do modo de aplicativo, pode encontrar e marcar todas as bordas ou interseções com um pequeno círculo vermelho. Um cusp marca o ponto onde um traço muda de direção abruptamente. Uma interseção marca um ponto em que um traço se cruza consigo mesmo ou com outro traço.
O evento Paint ocorre sempre que um controle é redesenhado.
Observação
O exemplo força o formulário a se redesenhar sempre que um traço é apagado ou quando o modo de aplicativo é alterado, usando o método Refresh do formulário.
private void InkErase_OnPaint(object sender, PaintEventArgs e)
{
Strokes strokesToPaint = myInkCollector.Ink.Strokes;
myInkCollector.Renderer.Draw(e.Graphics, strokesToPaint);
switch (mode)
{
case ApplicationMode.CuspErase:
PaintCusps(e.Graphics, strokesToPaint);
break;
case ApplicationMode.IntersectErase:
PaintIntersections(e.Graphics, strokesToPaint);
break;
}
}
No PaintCusps
, o código itera em cada cuspe em cada traço e desenha um círculo vermelho em torno dele. A propriedade PolylineCusps do traço retorna os índices dos pontos dentro de um stoke que correspondem a cuspes. Além disso, observe o método InkSpaceToPixel do objeto Renderer, que converte o ponto em coordenadas relevantes para o método DrawEllipse.
private void PaintCusps(Graphics g, Strokes strokesToPaint)
{
foreach (Stroke currentStroke in strokesToPaint)
{
int[] cusps = currentStroke.PolylineCusps;
foreach (int i in cusps)
{
Point pt = currentStroke.GetPoint(i);
// Convert the X, Y position to Window based pixel coordinates
myInkCollector.Renderer.InkSpaceToPixel(g, ref pt);
// Draw a red circle as the cusp position
g.DrawEllipse(Pens.Red, pt.X-3, pt.Y-3, 6, 6);
}
}
}
No PaintIntersections
, o código itera em cada traço para encontrar suas interseções com todo o conjunto de traços. Observe que o método FindIntersections do traço é passado por uma coleção Strokes e retorna uma matriz de valores de índice de ponto flutuante que representam as interseções. Em seguida, o código calcula uma coordenada X-Y para cada interseção e desenha um círculo vermelho ao redor dele.
private void PaintIntersections(Graphics g, Strokes strokesToPaint)
{
foreach (Stroke currentStroke in strokesToPaint)
{
float[] intersections = currentStroke.FindIntersections(strokesToPaint);
}
}
Manipulando uma caneta que tem duas extremidades
Três manipuladores de eventos são definidos para o objeto InkCollector para os eventos CursorDown, NewPackets e Stroke . Cada manipulador de eventos verifica a propriedade Invertida do objeto Cursor para ver qual final da caneta está sendo usada. Quando a caneta é invertida:
- O
myInkCollector_CursorDown
método torna o traço transparente. - O
myInkCollector_NewPackets
método apaga traços. - O
myInkCollector_Stroke
método cancela o evento. Os eventos NewPackets são gerados antes do evento Stroke .
Rastreando o cursor
Se o usuário estiver usando uma caneta ou um mouse, eventos MouseMove serão gerados. O manipulador de eventos MouseMove primeiro verifica se o modo atual é um modo de apagamento e se algum botão do mouse é pressionado e ignora o evento se esses estados não estiverem presentes. Em seguida, o manipulador de eventos converte as coordenadas de pixel do cursor em coordenadas de espaço à tinta usando o método PixelToInkSpace do objeto Renderer e chama um dos métodos de apagamento do código, dependendo do modo de apagamento atual.
Apagando traços
O EraseStrokes
método usa a localização do cursor no espaço à tinta e gera uma coleção de traços que estão dentro HitTestRadius
de unidades. O currentStroke
parâmetro especifica um objeto Stroke que não deve ser excluído. Em seguida, a coleção de traços é excluída do coletor e o formulário é redesenhado.
private void EraseStrokes(Point pt, Stroke currentStroke)
{
Strokes strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius);
if (null!=currentStroke && strokesHit.Contains(currentStroke))
{
strokesHit.Remove(currentStroke);
}
myInkCollector.Ink.DeleteStrokes(strokesHit);
if (strokesHit.Count > 0)
{
this.Refresh();
}
}
Apagando em interseções
O EraseAtIntersections
método itera sobre cada traço que se enquadra no raio de teste e gera uma matriz de interseções entre esse traço e todos os outros traços na coleção. Se nenhuma interseção for encontrada, esse traço inteiro será excluído; caso contrário, o ponto mais próximo do traço para o ponto de teste está localizado e, a partir disso, as interseções em ambos os lados do ponto estão localizadas, descrevendo o segmento a ser removido.
O método Split do objeto Stroke é usado para separar o segmento do restante do traço e, em seguida, o segmento é excluído, deixando o restante do traço intacto. Como em EraseStrokes
, o formulário é redesenhado antes que o método retorne.
private void EraseAtIntersections(Point pt)
{
Strokes strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius);
foreach (Stroke currentStroke in strokesHit)
{
float[] intersections = currentStroke.FindIntersections(myInkCollector.Ink.Strokes);
...
float findex = currentStroke.NearestPoint(pt);
...
strokeToDelete = currentStroke.Split(intersections[i]);
...
}
...
}
Apagando em Cusps
Para cada traço que se enquadra no raio de teste, o EraseAtCusps
método recupera a matriz de cuspes do método PolylineCusps do objeto Stroke. Cada extremidade do traço também é um limite, portanto, se o traço tiver apenas dois limites, todo o traço será excluído; caso contrário, o ponto mais próximo do traço para o ponto de teste está localizado e, a partir disso, as interseções em ambos os lados do ponto estão localizadas, descrevendo o segmento a ser removido.
O método Split do objeto Stroke é usado para separar o segmento do restante do traço e, em seguida, o segmento é excluído, deixando o restante do traço intacto. Como em EraseStrokes
, o formulário é redesenhado antes que o método retorne.
private void EraseAtCusps(Point pt)
{
...
strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius);
foreach (Stroke currentStroke in strokesHit)
{
int[] cusps = currentStroke.PolylineCusps;
...
float findex = currentStroke.NearestPoint(pt);
...
strokeToDelete = currentStroke.Split(cusps[i]);
myInkCollector.Ink.DeleteStroke(strokeToDelete);
...
}
...
}
Fechando o formulário
O método Dispose do formulário descarta o objeto InkCollector , myInkCollector
.