3 de Enero de 1999

Un programa de Dibujo II.

En el capítulo anterior vimos como empezar a dibujar usando la herramienta Canvas que Delphi ponia a nuestra disposición. Si habeís consultado la ayuda de Delphi, habreís visto que esta herramienta tiene una gran cantidad de propiedades y métodos. Por ahora me voy a centrar en la propiedad Pen (lápiz). Esta es una propiedad que apesar que tiene gran cantidad de opciones, su uso es fácil e intuitivo. Con ella podemos indicar de que manera se pinta, con que color, etc

Si consultas la ayuda de Delphi verás que dice que Pen es una propiedad del tipo TPen. Esta contiene una serie de propiedades para configurar el lápiz (pen).

Propiedades del lápiz (TPen)

Propiedad

Descripción

Mode Indica el modo en el que interactuará el lienzo y el lápiz.
Color Indica el color del lápiz que usaremos.
Style Estilo de la línea (discontinua, etc..)
Width Grosor de la línea.

La propiedad Width indica el ancho en pixels de la línea que vallamos a pintar. Su valor debe ser un entero (integer) igual a uno o superior. La propiedad Color indica el color con el cual va ser pintado la línea. Como valores admite los colores predefinidos por Windows, que son esos que aparecen el la propiedad Color de los componentes. Esta es la tabla de colores y sus equivalencias.

Tabla de principales colores

Color

Descripción

clBlack Negro
clMaroon    Marrón
clGreen Verde
clOlive Verde Oliva
clNavy Azul marino
clPurple Purpura
clTeal Verde Esmeralda
clGray Gris
clSilver Plata
clRed Rojo
clLime Verde Lima
clBlue Azul
clFuchsia Fusia
clAqua Agua
clWhite Blanco

Otra propiedad es Style, como ya comenté, que contiene el "estilo" con el que dibuja el lápiz, estas son sus valores.

Nombre Descripción

psSolid  

Una línea solida

psDash  

La línea esta compuesta de rayas

psDot  

La línea es compuesta de puntos

psDashDot  

Línea compuesta de puntos y raya

psDashDotDot  

La línea se compone de raya punto punto

psClear  

La línea no es dibujada, se usa para dibujar formas básicas (rectangulos, etc) con relleno, pero sin perímetro

psInsideFrame  

Una línea solida,pero el color puede variar si el ancho del lápiz es mayor de uno.

Si aplicas los estilos al programa que tenemos es probable que no se aprecien, y eso es debido a la manera que dibujamos la línea, este problemilla lo solucionaré más adelante. Por ahora quedaros con los diversos tipos de línea que hay, ya que antes he de hablaros de la propiedad Mode. Esta propiedad indica como interactuan el lápiz con el el lienzo (Pen con Canvas), vamos a ver los posibles valores que puede tomar esta propiedad.

Nombre Descripción

pmBlack  

Siempre pinta en negro

pmWhite  

Siempre pinta en blanco

pmNop  

No realiza ningun cambio, osea no pinta

pmNot  

Invierte el color del lienzo

pmCopy  

Usa el color especificado en la propiedad Color

pmNotCopy  

Usa el color inverso al especificado en la propiedad Color

pmMergePenNot 

Combina el color del lápiz y el color inverso del lienzo.

pmMaskPenNot 

Combina el color del lápiz y el color inverso del lienzo. Pero solo teniendo en cuenta su color común

pmMergeNotPen 

Combinación del color de fondo del lienzo y el color inverso del lápiz.

pmMaskNotPen

Combinación de los colores del fondo del lienzo y el color inverso del lápiz, pero solo teniendo en cuenta los colores comunes.

pmMerge  

Combinación del color del lápiz y del color de fondo del lienzo.

pmNotMerge  

El inverso a pmMerge

pmMask  

Combinación de colores comunes del lápiz y del fondo del lienzo.

pmNotMask  

El inverso del pmMask

pmXor  

Color del lápiz o del lienzo

pmNotXor  

Lo contrario del pmXor.

Una cosa que hay que tener en cuenta, es que windows trabaja con colores RGB (Red, Green, Blue; rojo, verde, azul), para generar toda la mezcla de colores, por eso cuando se habla de colores comunes se refiere a las tonalidades de los colores base (rgb) que coinciden en un coinciden. Por otra parte de todos los modos aqui mostrados el más interesante en pmXor, la mejor manera de saber lo que hace cada uno es probandolos.

De todos los modos de dibujo, el más socorrido y el que vamos a usar es el pmNotXor. Este modo tiene la particularidad que si dibujamos una línea, por ejemplo, y después vuelves a dibujar la línea de nuevo por encima de la que estaba, esta se borra, y queda como si no hubieras dibujada nada.Esto lo vamos a usar para crear el efecto que tienen los programas de dibujo, los cuales cuando dibujas un línea esta se se va dibujando a medida que mueves el ratón, y puedes ir cambiando el  destino, y cuando dejas de dibujar (sueltas el botón por ejemplo), la línea queda dibujada desde el origen hasta donde esta el cursor del ratón.

Así que tenemos que hacer algunas modificaciones al programa. Para conseguir esto debemos guardar en un variable el punto de donde partimos, osea donde el usuario ha pulsado el botón del ratón. Además tenemos que introducir otra variable más, la cual contendrá la posición anterior del ratón, osea, cada vez que se ejecute el evento MouseMove deberemos pintar la línea desde el origen hasta donde estaba el ratón antes de producirse ese evento usando el modo pmNotXor, con lo que logramos borrar la línea que habiamos pintado, despues pintamos una nueva línea desde el origen hasta el punto donde esta el ratón (ojo que he dicho está, y no estaba, este punto es indicado por las variables X e Y del evento). Una vez pintada la línea "nueva", guardamos el punto donde esta el ratón, así cuando se vuelva a ejecutar el evento tendremos guardado el punto donde estaba el ratón en el evento anterior, a esta variable la llamaré Punto.Las dos nuevas variables son del tipo TPoint, el cual es un tipo de variable definida por Delphi, la cual contiene las coordenadas de un punto. Fijate que las dos variables están definidas en la sección privada del formulario para que sean accesibles a todos los procedimientos del formulario.


unit uEjemplo2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    Pintando : Boolean;
    Origen,
    Punto : TPoint;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
 Pintando := False;
 Image1.Canvas.Refresh;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 If Button = mbLeft Then
 Begin
   Pintando := True;
   Image1.Canvas.MoveTo (X,Y);
   Origen := Point (X,Y);
   Punto := Point (X,Y);
 end;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
 If Pintando Then
  With Image1 Do
  Begin
    Canvas.Pen.Mode := pmNotXor;
    Canvas.MoveTo (Origen.X,Origen.Y);
    Canvas.LineTo (Punto.X,Punto.Y);
    Canvas.MoveTo (Origen.X,Origen.Y);
    Canvas.LineTo (X,Y);
  end;
  Punto := Point (X,Y);
  Image1.Canvas.Pen.Mode := pmCopy;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 If Button = mbLeft Then
  pintando := False;
end;

end.

Si te fijas en el evento MouseMove, despues del If, hay una línea que pone With Image1 Do, esta orden no tiene efecto sobre la ejecución del programa, pero si sobre su compilación. Lo que hace esta línea realmente, es ahorrar tiempo a la hora de escribir y ayudar a clarificar el código. Esta línea lo que indica es que todos los métodos o propiedades s que vienen después son aplicadas al componente Image1. Este cuadro te aclarará más las cosas.

Sin With Image1 Do Con  With Image1 Do

   Image1.Canvas.Pen.Mode := pmNotXor;
   Image1.Canvas.MoveTo (Origen.X,Origen.Y);
   Image1.Canvas.LineTo (Punto.X,Punto.Y);
   Image1.Canvas.MoveTo (Origen.X,Origen.Y);
   Image1.Canvas.LineTo (X,Y);

    Canvas.Pen.Mode := pmNotXor;
    Canvas.MoveTo (Origen.X,Origen.Y);
    Canvas.LineTo (Punto.X,Punto.Y);
    Canvas.MoveTo (Origen.X,Origen.Y);
    Canvas.LineTo (X,Y);

 

Hasta ahora solo hemos dibujado lineas, pero se puede dibujar formas básicas (rectángulos, circulos, etc.). Las principales formas las veremos en el próximo capítulo, además usaremos una variable cuyo contenido lo definiremos nosotros. Los libros se suelen referir a ellas como tipos de datos definidos por el usuario.