Está en la página 1de 41

Captulo 7

Dibujar y Pintar
Para pintar los grficos (incluyendo texto), as como para mostrar los elementos que
componen una interfaz de usuario, Windows utiliza la interfaz de dispositivos grficos
(G!"Graphics Device Interface), la cual se encarga de llamar a las rutinas de los distintos
gestores de dispositivo (drivers de vdeo, de impresora y de trazadores grficos) que son los
que directamente act#an so$re el dispositivo% ic&o de otra forma, la interfaz de dispositivos
grficos ese el medio de Windows proporciona para di$u'ar so$re dispositivos grficos%
Puesto que existen muc&os dispositivos grficos de salida diferentes soportados por
Windows, unos de los o$'etivos principales de la G!" es permitir mostrar los grficos
independientemente del dispositivo utilizado% e esta forma podemos escri$ir aplicaciones
que se e'ecuten independientemente de las caractersticas particulares del dispositivo grfico
de salida que utilice una determinada mquina%
(os dispositivos grficos se pueden agrupar en) dispositivos matriciales (dispositivos
raster) y dispositivos vectoriales% (os dispositivos matriciales representan los grficos como
una matriz de puntos* pertenecen a este grupo los adaptadores de vdeo y las impresoras
(matriciales y lser)% +n cam$io, los dispositivos vectoriales, como los trazadores grficos o
plotters, representan los grficos utilizando lneas% ,omo gran parte de la programaci-n
grfica tradicional est $asada exclusivamente en vectores, pero los dispositivos de salida
grficos en sus mayora utilizan puntos (pxeles) para mostrar los grficos, la G!" &a sido
escrita para ser utilizada como un sistema vectorial de di$u'o de alto nivel y tam$i.n para
manipular puntos, sistema de $a'o nivel% +sto esta ligado a la facilidad de Windows de
permitir utilizar un sistema de coordenadas virtual, manteniendo a la aplicaci-n ale'ada del
&ardware, o utilizar el sistema de coordenadas del dispositivo, acercando la aplicaci-n ms al
&ardware%
/tro tema a tener en cuenta es la resoluci-n grfica de los dispositivos y su capacidad
de color% Para que una aplicaci-n se a'uste a diferentes adaptadores de vdeo con diferentes
resoluciones, el lengua'e grfico tiene que proporcionar &erramientas para poder determinar
las caractersticas del &ardware, lo que nos permitir realizar los a'ustes necesarios% Por otra
parte, la G!" se &a construido para que el usuario no tenga que preocuparse
excesivamente de los colores, realizando ella la mayora de las conversiones seg#n la
capacidad de color del dispositivo%
,uando el dispositivo so$re el que se muestra la informaci-n es la pantalla, Windows
utiliza el rea del cliente de una ventana de la aplicaci-n para di$u'ar (Windows s-lo puede
mostrar informaci-n en el rea de cliente de una ventana)% Para informar so$re la necesidad
de realizar una operaci-n de di$u'o, la ventana generara un evento Paint, lo que provocara
que se e'ecute el controlador de este asociado con dic&o evento% +sto ocurre
automticamente en los siguiente casos)
,uando el tama0o de una ventana se modifica%
,uando un rea de una ventana cu$ierta por otra ventana se descu$re porque se
mueve o se cierra est #ltima% +l rea descu$ierta puede tam$i.n proceder de un men# que
se cierra o de un icono que se arrastra so$re dic&a rea%
,uando se realiza un desplazamiento de lo visualizado por la ventana (la ventana
tiene $arras de desplazamiento)%
,uando, utilizando el m.todo adecuado, se invalida todo o parte del rea de cliente de
una ventana%
+n la mayora de los casos en los que parte de una ventana es cu$ierta por otro
elemento, es Windows el que guarda en alg#n lugar en la memoria la informaci-n necesaria
para repintar dic&a ventana% ,uando esto no suceda as, &a$r que escri$ir el c-digo
necesario para que en respuesta al evento Paint pueda repintarse el rea descu$ierta%
(a parte de la ventana que se repinta (generalmente un rectngulo) se denomina
1regi-n no vlida2% Para automatizar el proceso de repintado Windows mantiene internamente
una 1estructura de informaci-n de di$u'o2 para cada ventana% +ntre esta informaci-n se
encuentran las coordenadas del rectngulo que define la regi-n no vlida% 3am$i.n, cuando
sea preciso, desde el c-digo se puede declarar no vlida para que se repinte (m.todo
Invalidate)%
,uando &a$lamos de pintar o de repintar una regi-n nos referimos a mostrar en esa
regi-n la informaci-n que en cada caso se requiera, sin importar si es texto, un di$u'o lineal o
un mapa de $its% Para cada caso, (a G!" proporciona las clases adecuadas%
SERVICIOS DE GDI+
(os servidores de G!" se englo$an en tres amplias categoras) grficos vectoriales 4,
imgenes y tipografa%
(os grficos vectoriales estn relacionados con el di$u'o de tipos primitivos (como
lneas, curvas y figuras) que se especifican mediante con'untos de puntos en un sistema de
coordenadas% Por e'emplo, una lnea recta puede especificarse mediante dos puntos) los que
definen sus extremos, y un rectngulo puede especificarse mediante un punto que indique la
u$icaci-n de sus esquina superior izquierda y un par de valores que indiquen el anc&o y el
alto% 5n trazado simple puede especificarse mediante la matriz de puntos que se conectaran
empleando lneas rectas para formar dic&o trazado% 5na lnea flexi$le (spline) es una curva
sofisticada, especificada por cuatro puntos de control%
Para realizar estos grficos vectoriales, G!" proporciona clases y estructuras que
realmente realizan el di$u'o% Por e'emplo, la estructura Rectangle almacena la u$icaci-n y el
tama0o de un rectngulo*6 la clase Pen almacena informaci-n so$re el color, anc&o y estilo
de lnea* la clase ru!" almacena informaci-n so$re el color* y la clase Grap"ic!
proporciona los m.todos para di$u'ar lneas, rectngulos, trazados y otras figuras%
5na imagen vectorial se puede registrar en un metarc&ivo como una secuencia de
-rdenes grficas% Para ello, la G!" proporciona las clases #eta$ile, #eta%ile&eader y
#eta&eader%
Por otra parte, imgenes como las mostradas por los $otones de una $arra de
&erramientas, iconos, o $ien una fotografi digital, son tipos de imgenes que, dependiendo
de los casos, son muy difciles de mostrar con las t.cnicas de grficos vectoriales, o
simplemente que no se pueden mostrar mediante esta t.cnica% Por eso, este tipo de
imgenes se almacenan como mapas de $its (matrices de n#meros que representan los
colores de puntos individuales de la pantalla)% G!" proporciona la clase it'ap para
mostrar, manipular y guardar mapas de $its%
7inalmente , la tipografa se ocupa de la presentaci-n de texto en diversas fuentes,
tama0os y estilos% Por e'emplo, una de las nuevas caractersticas de G!" es la funci-n de
alisado su$pxel que proporciona una apariencia ms regular al texto que se muestra en una
pantalla%
3odos los servicios de G!" son suministrados por un amplio con'unto de clases,
estructuras y enumeraciones agrupadas en los siguientes espacios de nom$res)
Sy!te'(Dra)ing( Proporciona acceso a los m.todos grficos $sicos de G!"%
Sy!te'(Dra)ing(Dra)ing*D% Proporciona m.todos grficos vectoriales y
$idimensionales avanzados% Por e'emplo, incluye los pinceles degradados, la clases #atri+
utilizada para definir transformaciones geom.tricas y la clase Grap"ic!Pat" que permite
conectar series de lneas y curvas%
Sy!te'(Dra)ing(I'aging( Proporciona m.todos para manipular imgenes
avanzadas%
Sy!te'(Dra)ing(,e+t( Proporciona m.todos para manipular las presentaci-n del
texto%
Sy!te'(Dra)ing(Printing( Proporciona servicios relacionados con la impresi-n%
O-E,OS DE DI.-O /SICOS
(a clase Grap"ic! es la $ase de la funcionalidad proporcionada por la G!") esta es, es la
clase que realmente di$u'a lneas, curvas, figuras, imgenes y texto%
8ntes de empezar a di$u'ar, de$e elegir la superficie en la que quiere di$u'ar, el tipo de
formas que desea di$u'ar y los instrumentos que utilizar para di$u'ar% (a superficie estar
representada por un o$'eto Grap"ic!, y sus m.todos permitirn di$u'ar todas las formas
$sicas% espu.s, elegiremos los instrumentos Pen (lpiz o pluma), para di$u'ar las formas,
y ru!" ($roc&a o pincel), para rellenar esas formas* seleccionaremos una $roc&a s-lo
cuando deseemos cam$iar el color de fondo% Por #ltimo, di$u'aremos la forma llamando al
m.todo adecuado de o$'eto Grap&ics% Por e'emplo, el siguiente c-digo di$u'a una lnea azul)
Graphics g = this.CreateGraphics ( );
Pen lapizAzul = new Pen ( Color.Blue );
Point puntoA = new Point ( 10, 10 );
Point puntoB = new Point ( 200, 100);
g.raw!ine (lapizAzul, puntoA, puntoB );
(a primera sentencia elige superficie correspondiente al o$'eto t"i! para di$u'ar% (a
sentencia siguiente crea un lpiz azul% (as dos sentencias siguientes definen los extremos de
la lnea a di$u'ar* las coordenadas estn expresadas en pxeles% 9 la #ltima sentencia di$u'a
una lnea llamando el m.todo Dra)0ine* este m.todo acepta como primer parmetro el
instrumento con el que se di$u'ar, y como siguientes parmetros los puntos de definen la
lnea a di$u'ar% +ste m.todo, como la mayora de los m.todos de Grap"ic!, presenta
m#ltiples formas* por e'emplo, puede omitir las definiciones de lpiz y de los puntos y
especificar como primer parmetro un lpiz de la clase Pen! y como siguientes parmetros
las coordenadas de los puntos que definen los extremos de las lneas)
Graphics g = this.CreateGraphics ( );
g.rawl!ine ( Pens.Blue, 10, 10, 200, 100) ;
3odas las coordenadas se expresan por defecto en pxeles, aunque, como veremos
mas adelante, es posi$le especificar las coordenadas en otras unidades, dependiendo de lo
que estemos di$u'ando, y de'ar que la G!" las convierta en pxeles antes de di$u'ar% +l
sistema de coordenadas predeterminado tiene el origen en la esquina superior izquierda de
la superficie de di$u'o, con el e'e : apuntando &acia la derec&a y el e'e 9 apuntando &acia
a$a'o)
Objeto Grap"ic!
+l o$'eto Grap"ic! es la superficie de di$u'o% ,ada control so$re el que se pueda di$u'ar
expone su superficie a trav.s de un o$'eto Grap"ic!%
Para recuperar el o$'eto Grap"ic! de un o$'eto &ay que invocar al m.todo
CreateGrap"ic! de ese o$'eto (en la mayora de los casos referenciado por t"i!))
Graphics g = this.CreateGraphics ();
(a sentencia anterior requerir importar el espacio de nom$res)
using "#ste$.rawing;
5na vez realizadas las operaciones anteriores, la aplicaci-n podr di$u'ar so$re la
superficie representada por el o$'eto Grap"ic!% Por e'emplo)
pri%ate %oi& 'ti'u(ar)Clic*(o'(ect sen&er, +%entArgs e)
,
Graphics g = CreateGraphics();
g,raw!ine(Pens.Blue, 10, 10, 200, 100);
-
+l m.todo anterior se corresponde con el controlador del evento Clic1 del $ot-n de
pulsaci-n btDibujar% (a primera sentencia recupera el o$'eto Grap&ics que representa la
superficie de di$u'o correspondiente al rea de cliente de una ventana 7orm;, la que
contiene $ot-n, y la segunda sentencia di$u'a una lnea azul definida por los puntos (;<, ;<)
y (4<<, ;<<)%
+l m.todo apropiado para iniciar el o$'eto Grap"ic! e insertar el c-digo de di$u'o es el
controlador del evento Paint del o$'eto al que corresponde la superficie de di$u'o, ya que
este evento es generado por un o$'eto cada vez que necesita repintarse% Por e'emplo)
pri%ate %oi& PictureBo.1)Paint(o'(ect sen&er, Paint+%entArgs e)
,
Graphics g = e.Graphics;
g.raw!ine(Pens.Blue, 10, 10, 200, 100);
-
+( m.todo anterior se corresponde con el controlador del evento Paint de un control
Pictureo+% (a primera sentencia recupera el o$'eto Grap&ics que representa la superficie
de di$u'o correspondiente al control PictureBox1 y la segunda di$u'a so$re esa superficie
una lnea azul definida por los puntos (;< ,;<) y (4<<, ;<<)% 8 diferencia del e'emplo anterior,
a&ora el o$'eto Grap&ics se o$tiene atreves del argumento e del controlador del evento
Paint%
8lgunas de las propiedades que proporciona la clase Grap&ics son) Dpi2 y Dpi3 que
especifican la resoluci-n &orizontal y vertical en pxeles por pulgada (una pulgada equivale a
4=,> milmetros) de la superficie de di$u'o* Page.nit que especifica la unidad empleada en el
sistema de coordenadas* ,e+tRendering&int que especifica si se procesar el texto con la
t.cnica de alisado* S'oot"ing#ode es anloga a la anterior pero aplica$le a todas las
formas, y no sol- al texto%
(a unidad de medida especificada por la propiedad Page.nit viene definida por los
miem$ros de la enumeraci-n Grap"ic!.nit especificados a continuaci-n)
Di!play4 unidad por omisi-n para el dispositivo de visualizaci-n* pxeles para la
pantalla y ;?;<< pulgadas para la impresora%
Docu'ent4 ;?@<< pulgadas%
Inc"4 una pulgada%
#illi'eter4 un milmetro %
P+el4 un pxel%
Point4 ;?A4 pulgadas%
5orld4 unidad universal%
(a clase Grap&ics tam$i.n proporciona los siguientes m.todos que explicaremos a
continuaci-n) Dra)0ine, Dra)Reetangle, Dra)Ellip!e, Dra)Polygon, Dra) 6rc,
Dra)Curve (para curvas flexi$les cardinales), Dra)e7ier (para curvas flexi$les de Bezier) y
Dra)String% ,ada uno de estos m.todos presenta m#ltiples formas* sirva como e'emplo el
m.todo Dra)0ine empleado en las explicaciones anteriores%
Objeto Color
+l o$'eto Color del espacio de nom$res Sy!te'(Dra)ing representa un color%
Por e'emplo)
pu'lic partial class /or$10 /or$
,
pri%ate Color color/on&o;
pri%ate Color colorPri$erPlano;
pria%e %oi& /or$1)!oa&( o'(ect sen&er, +%entArgs e)
,
color/on&o = Color.1hite;
colorPri$erPlano = Color.Blac*;
PictureBo.1.Bac*Color = color/on&o;
-
22 ...
pri%ate %oi& PictureBo.1)Paint( o'(ect sen&er , Paint+%entArgs e)
,
22 ...
-
-
+l e'emplo anterior define un color para el fondo de un o$'eto y otro para el primer
plano, como atri$utos de la clase Form1% espu.s, inicia am$as varia$les en el controlador
del evento 0oad del formulario con los colores $lanco y negro respectivamente% 7inalmente,
en el mismo controlador, esta$lece el color de fondo del control Pictureo+8 (propiedad
ac1Color)%
(a estructura Color dispone de ;4C atri$utos para definir toda una coleccion de
colores para elegir%
Objeto Pen
3odos los m.todos de di$u'o de la clase Grap"ic! operan 'unto con un o$'eto Pen* esto es,
para di$u'ar cualquier forma, de$en crearse como mnimo un o$'eto Grap"ic! para definir la
superficie de di$u'o y un o$'eto Pen que defina el c olor y el anc&o de lnea del elemento que
se va a di$u'ar% Por e'emplo)
pri%ate %oi& PictureBo.1)Paint(o'(ect sen&er, Paint+%entArgs e )
,
Pen l3piz4egro45 = new Pen(colorPri$erPlano, 5);
Graphics 6 = e . Graphics;
g.raw+llipse(l3piz4egro45, 10, 10, 200, 100);
-
+ste e'emplo define un lpiz, lpize!ro", de color negro y de anc&o tres pxeles que
posteriormente es utilizado por el m.todo Dra)Ellip!e para di$u'ar una elipse% Di se omite el
segundo argumento del constructor Pen, se creara por omisi-n un lpiz con una anc&ura de
un solo pxel%
+n los e'emplos iniciales vimos que tam$i.n existe una clase Pen! que proporciona
lpices de anc&o un pxel para todos los colores estndar% Por e'emplo, la siguiente sentencia
proporciona un lpiz negro de un pxel de anc&o)
Pens.Blac*;
Objeto ru!"
,uando se di$u'a una forma, por e'emplo un rectngulo o una elipse, se rellena con el color
de fondo actualmente esta$lecido% Para rellenarla con otro color s-lido con un patr-n o con
un mapa de $its &ay que crear una $roc&a o pincel (o$'eto ru!"9 y aplicarlo a la forma
invocando al m.todo adecuado% Por e'emplo)
"oli&Brush 'roacha"oli&a7er&e8ar =4ew "oli&Brush (Color.!ight"eaGreen);
Pen lapiz4egro45 = new Pen(colorPri$erPlano, 5);
Graphics g = e.Graphics;
g.raw+llipse(lapiz4egro45, 10, 10, 200, 100);
g./ill+llipse('rocha"oli&a7er&e8ar, 10, 10, 200, 100);
+ste e'emplo di$u'a una elipse y pinta todo su interior con la $roc&a brocha#olida
$erde%ar especificada% /$s.rvese que la $roc&a es un o$'eto de la clase Soliddru!"% +sto
es as porque Brus& es una clase a$stracta de la que se deriva los distintos tipos de $roc&as
que podemos utilizar y que indicamos a continuaci-n)
Brocha s&lida% /$'eto de la clase Solidru!"% 5tiliza un color s-lido para rellenar el
interior de una forma%
Brocha ra'ada( /$'eto de la clase &atc"ru!"% 5tiliza un rayado para rellenar el
interior de una forma (lneas verticales, &orizontales, en diagonal, etc%)%
Brocha de!radada% /$'eto de la clase 0inearGradientru!" (degradado lineal ) o de
la clase Pat"Gradientru!" (degradado de color)% 5tiliza colores que se irn degradando
mientras se rellena el interior de una forma%
Brocha textura( /$'eto de la clase ,e+tureru!"% 5tiliza una imagen para rellenar el
interior de una forma%
+l siguiente e'emplo di$u'a una elipse y pinta todo su interior con una $roc&a que
define un degradado &orizontal que cam$ia de azul a azul claro conforme se avanza del
$orde izquierdo de la elipse al $orde derec&o)
9ectangle rect = new 9ectangle(10, 10, 200, 100);
Graphics g = e.Graphics;
!inearGra&ientBrush 'rocharegra&a&a = new !inearGra&ie ntBrush(rect,
Color.Blue, Color . AliceBlue , !inearGra&ient8o&e.:orizontal );
g . /ill+llipse('rocharegra&a&a , rect);
Objeto Point
5n o$'eto Point representa un punto en la superficie de di$u'o y se expresa como un par de
coordenadas (x, y)% (a coordenada x es la distancia &orizontal desde el origen (<, <) 9 la
coordenada y es la distancia vertical desde el origen% Por e'emplo, el siguiente c-digo di$u'a
una lnea definida por los puntos ) y B)
Graphics 6 = e . Graphics;
Point A = new Point(10. 10);
Point B = new Point(200. 100);
g.raw!ine(Pens.Blue. A. B);
8lternativamente, puede declarar un o$'eto Point y despu.s asignar a sus
propiedades 2 e 3 los valores correspondientes%
ependiendo de las unidades en las que &aya definido el sistema de coor denadas
que est. utilizando, puede suceder que necesite expresar las coordenada no como un valor
entero, sino como un valor fraccionario* en este caso utilice o$'etos de tipo Point% que
definen sus atri$utos 2 e 3 de tipo $loat(
Objeto Rectangle
5n o$'eto Rectangle almacena cuatro enteros que representan la posici-n y tama 0o de un
rectngulo% Por e'emplo, el siguiente c-digo di$u'a la elipse que est inscrita en el rectngulo
rect utilizando la t.cnica de alisado)
Pen l3piz4egro45 = new Pen(colorPri$erPlano, 5);
Graphics 6 = e.Graphics;
g."$oothing8o&e = "$oothing8o&e.:igh;ualit#;
9ectangle rect = new 9ectangle(l<. 10. 200. 100);
g.raw+llipse(l3piz4egro45. 9ect);
(os dos primeros enteros de Eectangle indican la posici-n de la esquina superior
izquierda del rectngulo y los dos siguientes se corresponden con la anc&u ra y la altura,
respectivamente, del rectngulo%
5na alternativa a la definici-n anterior del o$'eto Rectangle es la siguiente)
Point p = new Point(l<. 10);
"ize &i$s = new "ize(200. 100);
9ectangle rect = new 9ectangle(p. i$s);
+n este e'emplo, el o$'eto Rectangle se define a partir de un o$'eto Point que define
la esquina superior del rectngulo y un o$'eto Si7e que define las dimen siones del
rectngulo%
8lternativamente, puede declarar un o$'eto Si7e y despu.s asignar a sus propiedades
5idt" y &eig"t los valores correspondientes%
Objeto %ont
5n /$'eto %ont define un formato concreto para el texto, incluidos el nom$re de la fuente% el
tama0o y el estilo% Para especificar una fuente, cree un o$'eto %ont, fi'e el nom$re de la
familia, el tama0o y el estilo, y aplquela cuando pinte el texto por e'emplo, invocando al
m.todo Dra)String% +l constructor %ont tiene muc&as formas* las ms sencillas permiten
crear el o$'eto %ont con el nom$re de la familia y el tama0o, o $ien con el nom$re de la
familia, el tama0o y el estilo% Por e'emplo)
pri%ate %oi& 'ti'u(ar)Clic*(o'(ect sen&er, +%entArgs e)
,
Graphics g = PictureBo.1.CreateGraphics();
/ont =uente = new /ont(>Arial>, 1?);
g.raw"tring(>@e.to a $ostrar>, =uente, Brushes.Blue, 10, 10);
-
+l m.todo anterior se corresponde con el controlador del evento Clic1 del $ot-n de
pulsaci-n btDibujar% (a primera sentencia recupera el o$'eto Grap"ic! que representa la
superficie de di$u'o correspondiente al control PictureBox1, la segunda crea un o$'eto %ont
que define la fuente F8rialF de tama0o ;G y la tercera di$u'a la cadena de caracteres F3exto a
mostrarF en la superficie grfica a partir de la posici-n (;<, ;<) en color azul%
+videntemente, una fuente puede crearse a partir de otra existente% De puede crear un
duplicado invocando al m.todo Clone, o simplemente una nueva referencia (sin utilizar
Clone)% Por e'emplo)
/ont =uenteActual = ( /ont )/ont.Clone();
(as propiedades %ont%a'ily, Si7e, Style, etc% son de s-lo lectura, lo que no permite
alterar una fuente ya creada% Para salvar este inconveniente, puede crear una fuente nueva
$asada en los valores de otra existente% Por e'emplo)
/ont =uente 4ue%a = new /ont( =uenteActual ./ont/a$il#, =uenteActual."ize A B,
=uenteActual."t#le C /ont"t#le.Bol&);
(a fuente nueva pertenece a la misma familia de la actual, su tama0o se &a incrementado en
cuatro unidades y tiene el mismo estilo ms negrita (old)%
Objeto Grap"ic!Pat"
+l o$'eto Grap"ic!Pat", denominado tam$i.n trazado, representa una serie de figuras
conectadas entre s (v.ase el apartado 3razados un poco ms adelante )%
#:,ODOS DE DI.-O
5na vez que se &an expuesto los o$'etos $sicos, vamos a centramos en los m.todos de
di$u'o, algunos de los cuales ya &an sido utilizados en los e'emplos anteriores%
3odos los m.todos de di$u'o tienen en com#n que su primer parmetro es un o$'eto
Pen, y los siguientes parmetros definen la forma a di$u'ar% Por otra parte los podemos
agrupar en dos categoras) los que di$u'an formas sin rellenar y los que di$u'an formas
rellenas* el nom$re de los primeros empieza por Dra) %%%, y el de los segundos por %ilI(((
Hstos #ltimos, a diferencia de los primeros, tiene como primer parmetro un o$'eto ru!"
que define el color con el que ser rellenada la forma di$u'ada%
0nea! y rect;ngulo!
Para di$u'ar una lnea, &ay que llamar al m.todo Dra)0ine del o$'eto Grap"ic!( Por
e'emplo, el c-digo siguiente di$u'a la lnea definida por los puntos (;< , ;<) y (4><, ;<<) en la
superficie g)
Graphics g= PictureBo.1.CreateGraphics() ;
Pen l3piz = new Pen(Color. Blac* . 5) ;
g .raw!ine( l3piz . 10 . 10 . 2B0 . 100) ;
+xisten varias formas del m.todo Dra)0ine y, adems, el o$'eto Pen tam$i.n expone
propiedades, como Da!"Style, que pueden utilizarse para especificar caractersticas de la
lnea% Por e'emplo, el siguiente c-digo di$u'a una lnea discontinua)
l3piz . ash"t#le = ash"t#le . ash ;
Point puntoA = new Point(10. 10) ;
Poi nt puntoB = new Point(2B0 . 100);
g.raw!ine(l3piz . puntoA. PuntoB) ;
i$u'ar rectngulos es parecido a di$u'ar lneas% 8&ora el m.todo utilizad o es
Dra)Rectangle, del que tam$i.n existen m#ltiples formas% 8 continuaci-n se pueden
o$servar dos formas diferentes de di$u'ar un mismo rectngulo )
g.raw9ectangle (l3piz, D0, E0, 200, 100);
9ectangle rect = new 9ectangle(D0, E0, 200, 100);
g.raw9ectangle(l3piz, rect);
Elip!e! y arco!
5na elepse se define mediante el rectngulo en el que est inscrita% +n la siguiente figura se
muestra una elipse 'unto con su rectngulo delimitador%
Para di$u'ar una elipse, utilizaremos el m.todo Dra)Ellip!e% +l primer argumento ser el
o$'eto Pen y el resto de los argumentos que se pasan especifican
el rectngulo delimitador de la elipse% Por e'emplo, la siguiente sentencia di$u'a
una elipse* el rectngulo delimitador tiene un anc&o de 4@<, un alto de I< y su esquina
superior izquierda coincide con el punto (;<, ;<))
g.raw+llipse(l3piz., 10 , 10, 250, 60);
Dra)Ellip!e es un m.todo so$recargado de la clase Grap"ic!, lo cual quiere decir que
existen varias formas de proporcionar argumentos a dic&o m.todo% Por e'emplo, se puede
construir un o$'eto Rectangle y pasarlo como segundo argumento)
9ectangle rect = new 9ectangle(l<. 120. 250. 60);
g .raw+llipse(l3piz. rect);
5n arco es una parte de una elipse% Para di$u'ar un arco, utilizaremos e l m.todo
Dra)6rc de la clase Grap"ic!% (os parmetros del m.todo Dra)6rc son los mismos que
los del m.todo Dra)Ellip!e, ms un ngulo inicial y un ngulo de $arrido% +n el siguiente
e'emplo se di$u'a un arco con un ngulo inicial de @< grados y un ngulo de $arrido de ;C<
grados )
g.rawArc( l3piz, rect , 50,1E0) ;
+l c-digo completo que da lugar a las formas mostradas en la figura anterior es el siguiente)
pri%ate %oi& 't+lipsesArcos)Clic*(o'(ect sen&er , +%entArgs e)
,
Graphics g = PictureBo.1.CreateGraphics() ;
Pen l3piz = new Pen(Color.Blac*);
l3piz.ash"t#le = "#ste$.rawing.rawing2.ash"t#le.ot;
g.raw9ectangle(l3piz , 10 , 10 , 250 , 60) ;
l3piz = new Pen(Color.Blac*, 5);
g.raw+llipse( l3piz, 10 , 10 , 250, 60);
9ectangle rect = new 9ectangle(10 , 120 , 250 , 60) ;
l3piz = new Pen(Colo r. Bl ac* , 5) ;
l3piz . ash"t#le = "#ste$.rawing.rawing2.ash"t#le.ot;
g.raw +llipse(l3piz , rect) ;
l3piz = new Pen(Color . 9e& , 5) ;
g.rawArc( l 3p i z , rect, 50 , 1E0) ;
-
,arta!
5n grfico de tarta es una forma parecida a una tarta* esto es, un arco 'unto con las dos
lneas que unen sus v.rtices en el centro de la elipse a la que pertenece el arco% Para di$u'ar
este tipo de grficos el o$'eto Grap"ic! proporciona el m.todo Dra)Pie que tiene como
parmetros los mismos que el m.todo Dra)6rc%
g.raw Pie(l3piz , rect, 50 , 1D0);
Polgono!
5n polgono es una forma cerrada definida por tres o ms puntos% Por e'emplo un tringulo y
un rectngulo son polgonos%
Para di$u'ar un polgono, son necesarios un o$'eto Grap"ic! que proporciona el
m.todo Dra)Polygon, un o$'eto Pen y una matriz de o$'etos Point ( o Point%)% +sta matriz
almacenar los puntos que se van a conectar mediante lneas rectas% +n el siguiente e'emplo
se di$u'a un polgono de cinco lados% Jay que colocar puntos en el orden en el que van a ser
recorridos% +l m.todo Dra)Polygon cierra el polgono de forma automtica%
Point/FG pent3go no = ,
new Point (20 , 1D0) ,
new Point (150, 120 ) ,
new Point(25 0 , 1D D) ,
new Poin t ( 160, 200) ,
new Poin t (BD, 16D)
-;
g.rawPol#gon ( l3piz, pent3gono) ;
Curva! $le+ible!
istinguimos dos tipos de curvas flexi$les) cardinales y de B.zier% 5na curva flexi$le cardinal
es una secuencia de curvas individuales com$inadas para formar una curva mayor* se
especifica mediante una matriz de puntos y un parmetro de tensi-n que por omisi-n vale <,=
, y se di$u'a invocando a Dra)Curve% 5na curva flexi$le de B.zier se especifica con cuatro
puntos) dos puntos correspondientes a los extremos (p1 y p*) y dos puntos de control (el y
e4)% (a curva comienza en p1 y aca$a en p4% (a curva no pasa por los puntos de control,
pero .stos se comportan como imanes, y tiran de la curva en ciertas direcciones e influyen
en el modo en que la curva se do$la% De di$u'a invocando a Dra)e7ier%
8 continuaci-n se muestra un e'emplo de dos curvas, una cardinal y otra de B.zier)
22 Puntos Hue &eInen la cur%a Je.i'le car&inal
PointF G puntos = ,
new Point (2D , 2D) ,
new Point(D0, 1D) ,
new Point(100 , D) ,
new Point( 120 , 2D) ,
new Point (1D0 , D0) ,
new Point(220 , 200) ,
new Point( 120, 120) );
22i'u(ar lKneas entre los puntos
g. raw!ines( l3piz9o(o , puntos) ;
22 i'u(ar la cur%a
g . rawCur%e( l3piz7er&e , puntos) ;
22 Puntos Hue &eInen la cur%a Je.i'le &e BLzier
Point p1 = new Point (50, 120);
Point p2 = new Point (1D0, 200);
Point c1 = new Point (MD, 10);
Point c2 = new Point (D0, 210);
22i'u(ar la cur%a
g.rawBezier (lapiz4egro, p1, c1, c2, p2);
,ra7ado!
5n trazado es un o$'eto de la clase Grap"ic!Pat"% De trata de una figura formada por una
secuencia de lneas, rectngulos, elipses, arcos, polgonos, curvas flexi$les, etc% cuyos
puntos inicial y final pueden o no ser coincidentes%
(a clase Grap&icsPat& proporciona varios m.todos para la creaci-n de una secuencia
de elementos que se van a di$u'ar) 6dd0ine, 6ddRectangle, 6dd Ellip!e, 6dd6rc,
6ddPolygon, 6ddCurve y 6dde7ier% ,ada uno de e stos m.todos admite varias formas% 8
continuaci-n se muestra un e'emplo)
Graphics g = PictureBo.1.CreateGraphics();
GraphicsPath traza&o = new GraphicsPath();
9ectangl e rect = new 9ectangl e (10. 10. 200. 100);
traza&o.A&&Arc(rect. BD.15D);
traza&o.A&&!ine(E0. 100. 1?0. 200);
traza&o.Close/igure();
g.rawPath(Pens.Blue. @raza&o);
5n trazado es una figura a$ierta, a menos que se cierre de forma explcita invocando
al m.todo Clo!e%igure, que cierra la figura actual con una lnea de el punto final &asta el
punto inicial% 5na figura formada por una forma geom.trica primitiva es una figura cerrada%
+sta forma de tra$a'ar puede ser interesante, por e'emplo, para di$u'ar varias veces el
mismo trazado, con un lpiz distinto, o rellenar las formas que comp onen el trazado con el
mismo degradado o mapa de $its, etc%
Regione!
5na regi-n es una parte de la superficie de di$u'o de un dispositivo de salida% (as regiones
pueden ser simples (un #nico rectngulo) o comple'as (una com$inaci-n de polgonos y
curvas cerradas)% De utilizan a menudo para recortar, acci-n que implica restringir el di$u'o a
una determinada rea de presentaci-n (normalmente la parte que necesita una
actualizaci-n), y para compro$ar si se &izo clic con el rat-n en una cierta regi-n de la
pantalla%
De puede construir una regi-n a partir de un rectngulo o de un trazado tam$i.n se
pueden crear regiones comple'as mediante la com$inaci-n de regiones existentes% (a clase
Region proporciona los siguientes m.todos para com$ $inar regiones) Inter!ect, .nion,
2or, E+ciude y Co'ple'ent%
(a intersecci-n de dos regiones, Inter!ect, es el con'unto de todos los puntos que
pertenecen a am$as regiones% (a uni-n, .nion, es el con'unto de todos los puntos que
pertenecen a una u otra regi-n% +l m.todo 2or, aplicado a un par de regiones, genera una
regi-n que contiene todos los puntos que pertenecen a una regi-n o a otra, pero no a am$as%
+l m.todo E+clude< aplicado a un par de regiones genera una regi-n que contiene todos los
puntos que pertenecen a la primera que no estn en la segunda% +l complemento,
Co'ple'ent, de una regi-n es el con'unto de todos los puntos que no estn en la regi-n %
Para rellenar una regi-n, son necesarios un o$'eto Grap"ic!, que proporciona el m.todo
%illRegion, un o$'eto ru!" y un o$'eto Region% Por e'emplo, la siguiente sentencia rellena
una regi-n con un color s-lido)
g./ill9egion( 'rocha, regiNn);
,omo e'emplo vamos a escri$ir el controlador de un $ot-n FEegionesF que muestre
tres elipses solapadas como muestra la figura siguiente)
+l prop-sito es definir una regi-n que restrin'a el rea de di$u'o a los puntos que no
sean comunes a dos o ms elipses* esta regi-n reci$e el nom$re de regi-n de recorte% +l
di$u'o que realizaremos so$re la regi-n as definida consistir en trazar radios desde el
centro de la misma a intervalos de 4 grados% /$s.rvese en la figura anterior c-mo los radios
quedan recortados en los lmites de la regi-n% +sto implica invocar al m.todo SetClip del
o$'eto Grap"ic! para definir la regi-n de recorte% 8plicaremos tam$i.n una transformaci-n
que defina el e'e + positivo &acia arri$a y traslade el origen (<, <) al centro de la superficie de
di$u'o% (as transformaciones se explicarn con detalle en el apartado siguiente%
pri%ate %oi& 't9egiones)Clic*(o'(ect sen&er, +%entArgs e)
,
22 "uperIcie &e &i'u(o
Graphics g = PictureBo.l.CreateGraphics();
22!3piz
Pen l3piz = new PenCColor.Blac*. 5);
22 Centro &e la superIcie &e &i'u(o
int .Centro = PictureBo.l.1i&th 2 2;
int #Centro = PictureBo.l.:eight 2 2;
22 @rans=or$aciones0 e(e O positi%o hacia arri'a #
22 origen C<.<) en el centro
g.@rans=or$ = new 8atri.Cl, 0, 0, P1, .Centro, #Centro);
229ect3ngulos para tres elipses
9ectangle rect0= new 9ectangle(PD0, 0, 100, 100);
9ectangle rect1 = new 9ectangle(PM. PMD, 100, 100);
9ectangle rect2 = new 9ectangle(P65, PMD,100,100);
22 AQa&i$os tres elipses a un traza&o
GraphicsPath traza&o = new GraphicsPath();
traza&o.A&&+llipse(rect0);
traza&o.A&&+llipse(rect1);
traza&o.A&&+llipse(rect2);
22 Pintar el traza&o
g./illPathCBrushes.Oellow. traza&o);
22 Crear una regiNn con el traza&o
9egion regiNn = new 9egionCtraza&o);
22 eInir la regiNn &e recorte0
22 regiNn &e recorte actual intersecciNn o'(eto regiNn
g."etClip (regiNn. Co$'ine8o&e.Cntersect);
22i'u(ar ra&ios &es&e el origen. &e &os en &os gra&os
Joat PC = 5.lBlD6R?/;
Joat ra&io = 8ath.8in(.Centro. #Centro);
Joat a;
Joat .;
Joat #;
=or ( a= 0; a S 2 T PC; a A= PC 2 60)
,
. = "#ste$.Con%ert.@o"ingleCra&io T 8ath.Cos(a));
# = "#ste$.Con%ert.@o"ingleCra&io T 8ath."in(a));
g.raw!ine(Pens.9e&, 0, 0, .. #);
-
-
Para mayor facilidad en el desarrollo &emos definido un trazado% Ko o$stante
podramos &a$er definido cada elipse en un trazado y com$inar los tres trazados (las tres
elipses) directamente en una regi-n, com$inando las dos primeras y el resultado con la
tercera)
GraphicsPath traza&o0= new GraphicsPath();
traza&o<.A&&+llipse(rect0);
GraphicsPath traza&o1 = new GraphicsPath();
traza&ol.A&&+llipse(rect1);
GraphicsPath traza&o2 = new GraphicsPath();
traza&oR.A&&+llipse(rect2);
9egion region= new 9egion(traz&o0);
region.Uor (traza&o1);
region.Uor (traza&o2);
g./ill9egion (Brushes.Oellow, region);
GR6%ICOS PERSIS,E=,ES
+n el apartado anterior, para explicar los distintos o$'etos y m.todos grficos, construimos
una aplicaci-n que visualiza$a una ventana con varios $otones, cada uno de los cuales
mostra$a una forma diferente% Prue$e a e'ecutar la aplicaci-n% Jaga clic en un $ot-n para
mostrar un grfico% Linimice la ventana y a continuaci-n vu.lvala a su posici-n normal% MNu.
&a sucedidoO /$servar que el grfico ya no se muestra%
+n un caso como el descrito, sa$emos que la ventana produce el evento Paint para
indicar la necesidad de repintarse% Pues $ien, para que un grfico realizado con los m.todos
grficos (imgenes y texto) pueda ser reproducido automticamente cuando la ventana que
lo muestra produzca un evento Paint, la aplicaci-n de$e ser capaz de reproducirlo por alg#n
medio% e aqu el nom$re de grficos persistentes% 5na ventana produce el evento Paint
cuando)
De construye por primera vez%
De superpone encima de otra%
De minimiza y despu.s se maximiza%
,am$ia de tama0o%
+l c-digo de la aplicaci-n lo genera invocando al m.todo Invalidate%
Deg#n lo expuesto, para reproducir los grficos, &ay que incluir el c-digo necesario en
el m.todo que se e'ecute en respuesta al evento Paint% Por e'emplo)
pri%ate %oi& PictureBo.1)Paint(o'(ect sen&ero Paint+%entArgs e)
,
22 "uperIcie &e &i'u(o
Graphics g = e.Graphics;
22 !Kneas # rect3ngulos
Pen l3piz = new Pen(Color.Blac*. 5);
g.raw!ine(l3piz. 10. 10. 2B0. 100);
9ectangle rect = new 9ectangle(l<. 120. 250. 60);
g.raw9ectangle(l3piz. 9ect);
-
8&ora, cada vez que el control PictureBox1 produzca el evento Paint se re pintarpero a&ora
con grficos persistentes, lo encontrar en la carpeta ,ap-./Paint del , que acompa0a al
li$ro%
+sta t.cnica es $uena para aplicaciones que presentan un grfico en $ase a un c-digo
que se e'ecuta como respuesta al evento Paint, pero no para aplicaciones que di$u'en algo
en respuesta a acciones del usuario* por e'emplo, piense en un panel de di$u'o del estilo de
la aplicaci-n Paint de Windows* el usuario elige de una $arra de &erramientas la forma que
quiere di$u'ar y, utilizando el rat-n, di$u'a esa forma so$re la superficie% +n este caso, el
controlador del evento Paint no puede prever lo que el usuario va a di$u'ar y, por otro lado,
seguir la pista de lo di$u'ado para poder reproducirlo es una tarea un tanto complicada% (a
soluci-n para un caso como .ste es crear una superficie de di$u'o permanente y di$u'ar los
grficos so$re ella% e'ecutando el m.todo PictureBox10Paint% +l c-digo completo de la
aplicaci-n mencionada, pero a&ora con grficos persistentes, lo encontrar en la carpeta
,ap-./Paint del , que acompa0a al li$ro%
+sta t.cnica es $uena para aplicaciones que presentan un grfico en $ase a un c-digo
que se e'ecuta como respuesta al evento Paint, pero no para aplicaciones que di$u'en algo
en respuesta a acciones del usuario* por e'emplo, piense en un panel de di$u'o del estilo de
la aplicaci-n Paint de Windows* el usuario elige de una $arra de &erramientas la forma que
quiere di$u'ar y, utilizando el rat-n, di$u'a esa forma so$re la superficie% +n este caso, el
controlador del evento Paint no puede prever lo que el usuario va a di$u'ar y, por otro lado,
seguir la pista de lo di$u'ado para poder reproducirlo es una tarea un tanto complicada% (a
soluci-n para un caso como .ste es crear una superficie de di$u'o permanente y di$u'ar los
grficos so$re ella%
Para crear una superficie de di$u'o permanente, siga los pasos indicamos a continuaci-n)
1. ,ree un mapa de $its, o$'eto it'ap, del mismo tama0o que la superficie de di$u'o
del controlo del formulario%
2. 8signe el mapa de $its a la propiedad I'age del control o a la propiedad
ac1groundl'age del formulario%
5. ,ree la superficie de di$u'o desde el mapa de $its% +sta superficie es permanente
(m.todo %ro'l'age de Grap"ic!)%
B. Opcionalmente puede utilizar el mtodo Clear de Graphics para estable cer el color de fondo de
la superficie de dibujo.
(a funci-n 1btener1bjetoGraphics que se muestra a continuaci-n devuelve una
superficie de di$u'o permanente)
pri%ate Graphics <'tener<'(etoGraphics()
,
Bit$ap $apaBits =
new Bit$ap(PictureBo.l.1i&th. PictureBo.l.:eig
PictureBo.l.C$age = $apaBits;
Graphics g = Graphics./ro$l$age($apaBits);
return g;
-
+l m.todo siguiente utiliza la funci-n anterior para di$u'ar grficos persistentes)
pri%ate %oi& 't!ineas9ect)Clic*(o'(ect sen&ero +%entArgs el
,
Graphics g = <'tener<'(etoGraphics();
Pen lapiz = new Pen(Color.Blac*,5 );
g.raw(lapiz, 10, 10, 2B0, 100);
9ectangle rect = new 9ectangle(10, 120, 250, 60);
g.raw9ectangle (lapiz, rect);
-
+l c-digo completo de la aplicaci-n Formas, pero a&ora utilizando una superfice de
di$u'o permanente, lo encontrar en la carpeta ,ap-./FormasPermanentes del , que
acompa0a al li$ro%
SIS,E#6S DE COORDE=6D6S 3 ,R6=S%OR#6CIO=ES
espu.s de lo estudiado &asta a&ora, sa$emos que todas las coordenadas se expresan por
defecto en pxeles, aunque, seg#n se expuso anteriormente, es posi$le especificar las
coordenadas en otras unidades y de'ar que la G!" las convierta en pxeles antes de di$u'ar%
Por e'emplo, la sentencia siguiente di$u'a la lnea definida por los puntos (<, <) 9 (;<<,><) en
la superficie g (representada en la figura siguiente por el rectngulo de lneas punteadas) que
de forma predeterminada define el origen (/, /) en su esquina superior izquierda con el e'e
2 apuntando &acia la derec&a y el e'e 9 apuntando &acia a$a'o)
g.raw!ine (Pens.Blue, 0, 0, 100, B0)
Dupongamos que deseamos tra$a'ar con un sistema de coordenadas que tenga su
origen en el centro de la superficie de di$u'o en lugar de en la esquina superior izquierda%
,alcular las coordenadas del centro de la superficie de di$u'o es una tarea fcil% Por e'emplo,
si la superficie de di$u'o es la correspondiente a un control de la clase Pictureo+,
podramos realizar este clculo as)
int .Centro = PictureBo.1.1i&th 2 2;
int #Centro = PictureBo.1.:eight 2 2;
8&ora, si el punto (/, /) se traslada al punto (x,entro, y,entro), al di$u'ar la recta
so$re la superficie de di$u'o todos sus puntos tendrn que sufrir la misma traslaci-n* esto es,
las coordenadas : de todos los puntos de la recta tendrn que ser incrementadas en x,entro
y las coordenadas 9en y,entro%
(a operaci-n de traslaci-n reci$e el nom$re gen.rico de transformaci-n y se aplicara
enviando a la superficie g el mensa'e ,ran!late,ran!$or')
g.@ranslate@rans=or$(.Centro, #Centro);
Bsicamente &ay tres tipos de transformaciones) escalados, rotaciones y traslaciones%
3odas ellas se resuelven con operaciones con matrices% (as transfor ciones lineales como los
escalados y las rotaciones se resuelven con una multiplicaci-n de matrices, y las no lineales,
como las traslaciones, con una suma de matrices%
Por e'emplo, si se considera un punto en un plano como una matriz ; x4, se puede
transformar para realizar una traslaci-n sumndole una matriz ; x4)
31-- 4-) 5 3x,entro ',entro) 6 31--5x,entro 4-5',entro)
3am$i.n se puede transformar dic&o punto para realizar un escalado multiplicndolo
por una matriz 4x4% Por e'emplo, escalar por 4 el punto (;<<, ><) en la direcci-n del e'e : y
del e'e 9, se &ara as)
(;<< ><) x P (4,<) (< ,4)Q R (4<< C<)
8plicar una rotaci-n de I< grados al punto (;<<, ><) se &ara as)
(;<< ><) x P (<,;) (S; ,<)Q R (S>< ;<<)
Eeelegir en el e'e : el punto (;<<%><) se &ara as (equivale a &acer que el e'e apunte
&acia arri$a))
(;<< ><) x P (;,<) (< ,S;)Q R (;<< S><)
5na transformaci-n lineal (multiplicaci-n por una matriz 4x4) seguida de una traslaci-n
(adicion de una matriz ;x4) se denomina transformaci-n afn)
(;<< ><) x P (;,<) (< ,S;)Q " (x,entro y,entro) R (;<<" x,entro S><y,entro)
5na alternativa a una transformaci-n afn es almacenar la transformaci-n completa en
una matriz @x@% Para que esto funcione, &ay que almacenar un punto del plano en una matriz
; x@ con una tercera coordenada ficticia% (a t.cnica ms &a$itual es &acer que todas las
terceras coordenadas sean igual a ;% Por e'emplo, el punto (;<<x><) viene representado por
la matriz (;<< >< ;)% Deg#n lo expuesto, una alternativa a la transformaci-n afn anterior
(refle'ar en el e'e : ms traslaci-n expresada como multiplicaci-n por una #nica matriz @x@
es la siguiente)
(;<< >< ;) x P (;,<,x,entro) (< ,S;,9centro)(<,<,;)Q " (;<<"x,entro S><"y,entro)
+n este e'emplo, el resultado es que el punto (;<<, ><) se asigna al punto
(;<<"x,entro, S><"y,entro)% 3enga en cuenta que la tercera columna de la matriz @x@
contiene los n#meros <, <, ; % +sto siempre ser as para el caso de la matriz @x@ de una
transformaci-n afino (os n#meros importantes son los seis n#meros de las columnas ; 9 4%
(a parte superior izquierda 4x4 de la matriz representa la parte lineal de la transformaci-n, 9
las dos primeras entradas de la tercera fila representan la traslaci-n%
+n Gl", es posi$le almacenar una transformaci-n afn en un o$'eto #atri+% ,uando
se construye un o$'eto #atri+, s-lo se especifican los seis n#meros de las dos primeras
columnas, ya que la tercera columna de una matriz que representa una transformaci-n afn
siempre es (<, <, ;)% Deg#n esto, la sentencia siguiente construye la matriz que se muestra
en el e'emplo anterior)
g.@rans=or$ = new 8atri.(1, 0. 0. P1. .Centro. #centro);
(a clase #atri+ proporciona varios m.todos para generar una transformaci-n
compuesta) #ultiply, Rotate, Rotate6t, Scale, S"ear y ,ran!late% +n el siguiente e'emplo
se crea la matriz de una transformaci-n compuesta que, primero rota @< grados, despu.s
a'usta la escala en un factor de > en la direcci-n del e'e : y en un factor de C en la direcci-n
del e'e 9, y finalmente se traslada x,entro unidades en la direcci-n del e'e : e y,entro
unidades en la direcci-n del e'e 9)
Graphics g = PictureBo.l.CreateGraphics();
int .Centro = PictureBo.l.1i&th C 2;
int #Centro = PictureBo.l.:eight C 2;
8atri. $atriz = new 8atri.();
22 @rans=or$aciNn
$atriz.9otate(50);
$atriz."cale(B. E. 8atri.<r&er.Appen&);
$atriz.@ranslate(.Centro. #Centro. 8atri.<r&er.Appen&);
g.@rans=or$ = $atriz;
22 i'u(ar
GraphicsPath tr = new GraphicsPath();
tr.A&&!ine(<. 0.100.B0);
g.rawPath(Pens.Blue. tr);
(a matriz resultante de esta transformaci-n es la siguiente)
cos@<T 4sen@<T <

Ssen@<T 4cos@<T <
x,entro y,entro ;
+l orden en una transformaci-n compuesta es importante% +n general, un orden de
rotaci-n, a'uste de escala y traslaci-n no es lo mismo que un orden de a'ustete de escala,
rotaci-n y traslaci-n% 8nlogamente, el orden de multiplicaci-n matrices es importante% +n
general, ml6m46m@ no es lo mismo que m4%m;%m@ Por eso, los argumentos )ppend '
Prepend (valor por omisi-n) tienen su importancia )ppend indica que la nueva operaci-n se
aplica despu.s de la operaci-n antigua y Prepend que la nueva operaci-n se aplica antes de
la operaci-n antigua% Deg un esto, la transformaci-n del e'emplo anterior podra
especificarse tam$i.n as)
$atriz.@ranslate(.Centro. #Centro)
$atriz."cale(B. E)
$atriz.9otate(50)
+n el e'emplo anterior se puede o$servar que la transformaci-n se aplica a todos los
elementos del o$'eto Grap"ic! (superficie g), incluyendo el lpiz con el que se est
di$u'ando, raz-n por la que se denomina transformaci-n glo$al%
/$s.rvese que para crear una transformaci-n glo$al se crea un o$'eto #atri+ que
almacena la secuencia de transformaciones afines y se asigna a la propiedad ,ran!$or' de
la superficie de di$u'o% +n contraposici-n, una transformaci-n local se le aplica un elemento
especfico que se va a di$u'ar% Por e'emplo, un o$'eto Grap"ic!Pat" tiene un m.todo
,ran!$or' con un parmetro de tipo #atri+ que permite transformar los puntos de datos de
ese trazado%
22@rans=or$aciNn
$atriz.9otate(50);
$atriz."cale(B, E, 8atri.<r&er.Appen&);
$atri..@ranslate(.Centro, #Centro, 8atri.<r&er.Appen&);
22i'u(ar
GraphicsPath tr = new GraphicsPath();
tr.A&&!ine(0, 0, 100, B0);
tr.@rans=or$($atriz);
g.rawPath(Pens.Blue, tr);
+n este e'emplo, la transformaci-n se aplica s-lo al o$'eto tr y no se aplica, o en el
caso anterior, al o$'eto Pen%
(a clase Grap"ic! proporciona varios m.todos para generar una transformaci-n
compuesta) #ultiply,ran!$or', Rotate,ran!$or', Scale,ran!$or', ,ran!late,ran!$or' y
Re!et,ran!$or'% Deg#n esto, el e'emplo anterior podra escri$irse tam$i.n as)
g 9otate@rans=or$ (50) ;
g."cale@rans=or$ (1, 2, 8atri.<r&e r. Appe n&) ;
g.@ranslate@rans=or$(.Centro , #Centro , 8atri.<r&er . Appen&) ;
g.lraw!ine(Pens.Blue , 0, 0, 100 , B0) ;
,ipo! de !i!te'a! de coordenada!
G!" utiliza tres espacios de coordenadas) universales, de pgina y de dispositivo% ,uando
se realiza la llamada a !(Dra78ine3Pens(Blue, /, / ;<<, ><) , los puntos que se pasan al
m.todo Dra)0ine, (/, /) 9 (;<<, ><), se encuentran en el espacio de coordenadas
universales% 8ntes de que G!" pueda di$u'ar la lnea en la pantalla, las coordenadas tienen
que pasar por una secuencia de transformaciones) una para convertirlas de universales a
coordenadas de pgina y otra, para convertirlas de coordenadas de pgina a coordenadas
de dispositivo%
(a transformaci-n universal est definida por la propiedad ,ran!$or' del o$'eto
Grap"ic!% +l o$'eto #atri+ que define el valor por omisi-n de esta transformaci-n es) (;, <,
<, ;,<, <), en la que se puede o$servar que el escalado es ;, la rotaci-n y la traslaci-n /% 9 la
transformaci-n de pgina se manipula a trav.s de las propiedades Page.nit, cuyo valor
pertenece a la enumeraci-n Grap"ic!.nit,y PageScale de Grap"ic!%
(a unidad de medida en el espacio de coordenadas universales quedar definida por el
tama0o que se d. a la superficie l-gica de di$u'o (v.ase ms adelante , en +'ercicios
resueltos, la representaci-n de funciones)% +l espacio de coordenadas de pgina
(coordenadas de la superficie de di$u'o), por definici-n, tiene e l origen en la esquina superior
izquierda del rea del cliente y la unidad de medida, por omisi-n, es Di!play) pxel para la
pantalla% +ste espacio coincidir con el espacio de coordenadas del dispositivo cuando la
unidad de medida en .ste #ltimo sea tam$i.n el pxel, como ocurre con la pantalla%
,ran!$or'acione! de color
,ada pxel en una superficie G!" se representa como un vector de = dimensiones p R (r, g,
$, a, w), donde r, g, $ son las componentes de color, comprendidas entre y ;, a (alfa) es la
componente de transparencia, que tiene valores entre < (totalmente transparente) y ;
(opaco) y w, necesaria para poder &acer transformaciones gen.ricas, vale siempre ;% Pues
$ien, un pxel p de una superficie se transforma en otro pxel p , mediante la relaci-n)
p96p,
donde , es una matriz de transformaci-n = x= especificada por el usuario, como se
muestra a continuaci-n, y encapsulada en un o$'eto de la clase Color#atri+4
(a #ltima columna de$e ser (<, <, <, <, ;) para que el pxel resultante son
&omog.neo* es decir, tenga w R ;% (a quinta fila de la matriz normalmente
tam$i.n es (<, <, <, <, ;)%
Ueamos, por e'emplo, qu. ocurre cuando transformamos un pxel (x,g, $, ;, ;), seg#n
la siguiente matriz de transformaci-n)
+n el resultado se o$serva que)
(a componente r99 del vector resultante depende s-lo de los elementos de la primera
columna de la matriz%
(a componente g F de los de la segunda columna%
(a componente $ F de los de la tercera columna%
9 la componente a, de los de la cuarta columna%
e a& que a la primera columna se la llame r, a la segunda !, a la tercera b y
a la cuarta a%
+ntonces, si en la matriz &acemos rV R $V R gV, para i R /, ; 9 4, o$tenemos una
transformaci-n con los valores r, g, $ de cada pxel id.nticos, independientemente
el color del pxel original, lo cual define una escala de !rises% +l siguiente e'emplo sera una
aplicaci-n de lo expuesto)
pri%ate %oi& <pciones+scalaeGrises)Clic*(o'(ect sen&er, +%entArgs e)
,
C$age i$agen = cil$agen.l$age;
using (Graphics g=. = Graphics./ro$l$age(i$agen))
,
22 8atriz para realizar una trans=or$aciNn a escala &e grises
22 $antenien&o los %alores &e lu$inancia.
Color8atri. c$ = new Color8atri.(new JoatF GF G
,
new JoatF G ,0.5=, 0.5=, <.5=, 0, 0 -,
new JoatF G ,0.D6=, 0.D6=, 0.D6=, 0, 0-,
new JoatF G ,0.11=, 0.11=, <011=, 0, 0-,
new JoatF G ,0, 0, 0,1, 0-,
new JoatF G ,0, 0, 0, 0, 1-
-) ;
C$ageAttri'utes ia = new C$ageAttri'utes();
ia."etColor8atri.(c$);
22 Vtilizar el $Lto&o rawl$age &e g=. para %ol%er a &i'u(ar la
22 i$agen utilizan&o los atri'utos especiIca&os por ia
g=..rawl$age(i$agen,
new 9ectangle (0. 0. i$agen.1i&th. i$agen.:eigh),
0. 0. i$agen.1i&th. i$agen.:eight ,
GraphicsVnit.Pi.el. Ca ) ;
-
cil$agen.9e=resh();
-
8nlogamente, si queremos una transformaci-n para o$tener una escala de ro'os, no
tendremos ms que tomar g R $ R <, de forma que el pxel resultante tendr solamente
componente r% (os valores que eli'amos para ro, rV y r4 determinarn las dems propiedades
de la imagen resultante (luminosidad, contraste, etc%)%
,omo #ltimo e'emplo, se puede demostrar que la matriz
convierte una imagen en semitransparente ya que de'a las componentes r,g,& inalteradas y
multiplica a por <,=%
#OS,R6R I#/GE=ES
esarrollando con %K+3 se puede di$u'ar en casi todos los controles% Ko o$stante lo normal
es di$u'ar en un formulario, o$'eto de la clase %or', o en una ca'a de imagen, o$'eto de la
clase Pictureo+(
+n los e'ercicios realizados anteriormente en este captulo &emos visto como di$u'ar
grficos vectoriales tanto en un formulario como en una ca'a de imagen% 8&ora vamos a ver
c-mo mostrar una imagen almacenada como mapa de $its
#apa! de bit!
5n mapa de $its es una matriz rectangular que almacena el color de cada pxel del mapa% +l
n#mero de $its asignado a un pxel individual determina el n#mero de colores que se pueden
asignar a dic&o pxel% Por e'emplo, si cada pxel se representa con 4> $its, a un pxel
determinado se le podr asignar uno entre los 4W4>R AAAA?4;G colores distintos% (a siguiente
figura muestra un mapa de $ita que almacena los colores de pxeles (CxC pxeles de 4> $its)
que forman el mapa)
+n el mapa de $its, 777777 representa el $lanco, 77//// representa el ro'o,
<<77<< representa el verde y ////77 representa el azul%
+xisten muc&os formatos estndar para almacenar mapas de $its en fic&eros de disco%
G!" soporta los siguientes)
BLP% Bit LaP, mapa de $its% Ko suelen comprimirse, por lo que no son muy
apropiados para que se transfieran a trav.s de !nternet%
G!7% Grap&ics !nterc&ange 7ormat, formato de intercam$io de grficos% De comprimen,
sin que se pierda informaci-n, por lo que son muy apropiados para que se transfieran a
trav.s de !nternet% 8s mismo, se puede especificar un color como transparente, de forma
que la imagen tenga el color de fondo de cualquier pgina We$ en la que se muestre, y
puede almacenarse en un #nico fic&ero una secuencia de imgenes G!7 para formar un G!7
animado% 3ienen una limitaci-n y es que almacenan como mximo C $its por pxel, por lo que
se limitan a 4=G colores%
XP+G% Xoint P&otograp&ic +xperts Group, grupo con'unto de expertos en fotografia%
Don muy adecuados para fotografias escaneadas% 8l comprimirlos se pierde algo de
informaci-n, pero la p.rdida suele ser impercepti$le para el o'o &umano% De almacenan 4>
$its por pxel y no admiten transparencia ni animaci-n%
+:!7% +xc&angea$le !mage 7ile, fic&ero de imagen intercam$ia$le% Don muy
adecuados para fotografias que se capturan con cmaras digitales% 5n fic&ero +:!7 contiene
una imagen comprimida conforme a la especificaci-n XP+G y, adems, almacena
informaci-n acerca de la fotografa (fec&a de toma, velocidad de o$turaci-n, tiempo de
exposici-n, etc%) e informaci-n acerca de la cmara (fa$ricante, modelo, etc.tera)%
PKG% Porta$le KetworY Grap&ics, grficos de red porttiles% +l formato PKG supone
una me'ora con respecto al formato G!7 por su capacidad para mostrar una imagen
progresivamente* es decir, para mostrar aproximaciones cada vez me'ores de la imagen a
medida que .sta llega a trav.s de una conexi-n de red% 8l igual que los arc&ivos G!7, los
arc&ivos PKG se comprimen sin que se pierda informaci-n% Pueden almacenar colores con C,
4> - >C $its por pxel y escalas de grises con ;,4,>,C - ;G $its por pxel, y tam$i.n puede
almac enar un valor alfa para cada pxel, que especifica el grado de mezcla de ese p ixel con
el color de fondo%
3!77% 3ag !mage 7ile 7ormaZ, formato de fic&ero de imgenes con etiqu etas% Pueden
almacenar imgenes con un n#mero ar$itrario de $its por pxel y pueden emplear varios
algoritmos de compresi-n%
Cargar y 'o!trar un 'apa de bit!
8nlogamente a la clase #eta$ile, que puede utilizarse para cargar y mostrar r imgenes
vectoriales, la clase it'ap puede utilizarse para cargar y mostrar imgenes de trama o
mapas de $its% 8m$as clases se derivan de la clase I'age% para mostrar una imagen
vectorial son necesarios un o$'eto Grap"ic! (o$'eto que proporciona el m.todo Dra)l'age)
y un o$'eto #eta$ile (imagen a mostrar) para mostrar un mapa de $its, son tam$i.n
necesarios un o$'eto Grap"ic! y la imagen a mostrar, que en este caso estar almacenada
en un o$'eto it'ap%
,omo e'emplo, vamos a construir una aplicaci-n que &aga las veces de visor de
imgenes sencillo% Du interfaz estar formada por una ventana con una $arra de men#s, una
$arra de &erramientas, una $arra de estado, un panel con $arras de desplazamiento y un
control Pictureo+ para mostrar las imgenes%
!nicie Uisual ,[ y cree un nuevo proyecto para implementar el esqueleto para una
nueva aplicaci-n que utilice un formulario de tipo %or' como ventana principal% enomnela
$isorlma!s% Ponga al formulario como ttulo FUisor de imgenesF y como nom$re FormI% 8
continuaci-n, a0ada las $arras de men# (#enuStrip), de &erramientas (,oolStrip) y de
estado (Statu!Strip)% espu.s complete la $arra de men#s con los elementos indicados en
la ta$la que se expone a continuaci-n (el c-digo completo lo encontrar en la carpeta
,ap-./$is orIma!e del , que acompa0a al li$ro))
Objeto Propiedad Valor
8rc&ivo Kame
3ext
Lenu8rc&ivo
8rc&ivo
8$rir Kame
3ext
8rc&ivo8$rir
8$rir%%%
Guardar ,omo Kame
3ext
8rc&ivoGuardar,omo
Guardar como%%%
,errar Kame 8rc&ivoDeparador;
Dalir Kame
3ext
8rc&ivoDalir
Dalir
/pciones Kame
3ext
Lenu/pciones
/pciones
3ama0o a'ustado Kame
3ext
/pciones3am8'ustado
3ama0o a'ustado
3ama0o real Kame
3ext
/pciones3amEeal
3ama0o real
8cercar Kame
3ext
/pciones8cercar
8le'ar Kame
3ext
/pciones8le'ar
8le'ar
Girar I<T Kame
3ext
/pcionesGirarI<
Girar I<T
Deparador Kame /pcionesDeparador;
,opiar Kame
3ext
/pciones,opiar
,opiar
8yuda Kame
3ext
Lenu8yuda
\8yuda
8cerca de Kame
3ext
8yuda8cercae
\8cerca de visor de
imagenes%%%%
5na vez dise0ada la $arra de men#s, a0ada un panel (o$'eto de la clasePanel( 8
continuaci-n, a'uste el tama0o del panel al tama0o del rea de cliente del formulario (y lado a
lado con la $arra de &erramientas)% espu.s, asigne a su propiedad 6utoScroll el valor true,
para permitir $arras de desplazamiento, a Doc1 el valor one y a 6nc"or los valores :op,
Bottom, 8eft y ;i!ht%
7inalmente, a0ada so$re el panel un control Pictureo+% 8signe a su propiedad =a'e
el valor cilmagen a su propiedad 0ocation el valor (/, /) y a su propiedad Si7e#ode el valor
)uto#ize(
MPor qu. no &emos a0adido el Pictureo+ directamente so$re el formulario, poniendo
la propiedad 6utoScroll de .ste a trueO Porque los controles #trip, por e'emplo #enuStrip,
residen en el rea de cliente (sus &om-logos, por e'emplo #ain#enu, residen en el rea de
no cliente) y seran desplazados al actuar so$re las $arras de desplazamiento del formulario%
5n control Pictureo+ permite mostrar grficos almacenados en un fic&ero de mapa
de $its, metarc&ivo o icono% Para mostrar un grfico $asta con asignar a su propiedad I'age,
durante el dise0o o durante la e'ecuci-n, el o$'eto I'age que desea mostrar% (a forma en la
que tiene lugar la presentaci-n es controlada por la propiedad Si7e#ode* los valores de esta
propiedad son definidos por la enumeraci-n Pictureo+Si7e#ode4
8utoDize% +l tama0o del Pictureo+ de$e a'ustarse al tama0o de la imagen que
contiene%
,enterlmage% (a imagen se muestra en el centro si el tama0o del Pictureo + es
mayor que el de la imagen% Di la imagen es ms grande, se coloca en e l centro del
Pictureo+ y se recortan los $ordes exteriores%
Kormal% (a imagen se coloca en la esquina superior izquierda del Pictureo+% Di la
imagen es ms grande que el o$'eto Pictureo+ que la contiene, se recorta%
Dtretc&lmage% (a imagen se a'usta al tama0o del Pictureo+ estirndose o
contray.ndose lo necesario%
]oom% +l tama0o de la imagen aumenta o disminuye en funci-n del tama0 o del
Pictureo+ pero manteniendo la misma proporcionalidad%
De puede cam$iar el tama0o del rea de presentaci-n en tiempo de e'ecuci-n con la
propiedad ClientSi7e% Para proporcionar un $orde estndar o tridimensional, utilice la
propiedad orderStyle(
Diguiendo con el desarrollo de la aplicaci-n, vamos a implementar las -rdenes del
men# 8rc&ivo% (a orden Dalir simplemente tiene que invocar al m.todo Clo!e de 7orm; para
cerrar el formulario y la orden ,errar asignar a la propiedad I'age del Pictureo+ el valor
null%
(a orden )brir tiene que permitir cargar un fic&ero $mp, gif, 'peg (o 'pg) png, exi'o tiff y
mostrarlo en la ca'a de imagen cilma!en% Para ello, a0ada el controlador correspondiente y
edtelo como se muestra a continuaci-n)
pri%ate %oi& Archi%oA'rir)Clic*(o'(ect sen&er, +%entArgs e)
,
<pen/ileialog lgA'rir = new <pen/ileialog();
lgA'rir .l nitialirector# = irector#.GetCurrentirector#();
lgA'rir./ilter = >/icheros B8PCT.'$p> A
> /icheros GC/CT.gi=> A
> /icheros WPG o WP+GCT .(pg;T.( peg > A
> /icheros P4GCT.png> A
> /icheros +UC/CT.e.i=> A
> /icheros @C//CT .tiX>;
lgA'rir./ilterCn&e. = 5;
igC$agen.C$age= C$age./ro$/ile(alA'rir./ile4a$e);
228ostrar el &ialogo a'rir
i= (igA'rir."wowialog( ) == ialogo9esult.<Y)
ig$agen.C$age = C$age./ro$/ile(igA'rir./ile4a$e);
-
(a propiedaad I'age del control Pictureo+ es un o$'eto I'age que contiene el
mapa de $its actual y expone propiedades y m.todos que permiten manipular esta imagen
(en el caso de un formulario &a$laramos de la propiedad ac1groundI'age)% ,omo la
clase it'ap est derivada de I'age, puede tam$i.n crear un o$'eto it'ap y asignrselo
a la propiedad I'age)
Bit$ap $apaeBits = new Bit$ap(lgA'rir./ile4a$e);
igC$agen =$apaeBits;
(a orden en Guardar como tiene que permitir guardar una imagen en un fic&ero bmp<
!if< jpe! 3o jp!)< pn!< exif o tiff% Para ello, a0ada el controlador correspondiente y editelo como
se muestra a continuaci-n)
pri%ate %oi& Archi%oGuar&arCo$o)Clic*(o'(ect sen&er , +%entArgs e)
,
"a%e/ileialog lgGuar&ar = new "a%e/ileialog();
lgGuar&ar.lnitialirector# = irector#.GetCurrentirector#();
lgGuar&ar ./ilter = >/icheros B8PCT.'$p> A
> Z/icheros GC/CT.gi=> A
> Z/icheros WPG o WP+GCT.(pg;T.(peg> A
> Z/icheros P4GCT.png> A
> Z/icheros +UC/CT.e.i=> A
> Z/icheros @C//CT.tiX>;
lgGuar&ar ./ilterln&e. = 5;
i= (l gGuar&ar."howialog() == ialog9esult.<Y)
,
22 Guar&ar la i$agen el Ichero
C$age/or$ at =or$ato = C$age/or$at.Wpeg;
switch (lgGuar&ar./ilterln&e.)
,
case 10
=or$ato = C$age/or$at.B$p;
'rea*;
case 20
=or$ato = C$age/or$at.Gi=;
'rea*;
case 50
=or$ato= C$age/or$at.Wpeg;
'rea*;
case B0
=or$ato = C$age/or$at.Png;
'rea*;
case D0
=or$ato = C$age/or$at.+.i=;
'rea*;
case ?0
=or$ato = C$age/or$at.@iX;
'rea*;
-
ciC$agen.C$age."a%e(lgGuar&ar./ile4a$e, =or$ato);
-
-
Para guardar una imagen &ay que utilizar el m.todo Save del o$'eto I'age que
contiene dic&a imagen% +ste m.todo presenta varias formas* la que &emos utilizado aqu
tiene dos parmetros) el nom$re del fic&ero y el formato con el que se guardar la imagen%
(os diferentes formatos estn definidos en la clase I'age%or'at perteneciente al espacio
de nom$res Sy!te'(Dra)ing(I'aging, por lo que si no se quiere utilizar el nom$re completo
para el formato deseado, &a$r que declarar que se va a utilizar esta $i$lioteca%
8 continuaci-n, vamos a implementar las -rdenes del men# 1pciones% (a orden
3ama0o a'ustado tiene que presentar la imagen &aciendo que su tama0o sea proporcional al
tama0o de la ca'a de imagen, l-gicamente conservando la proporcionalidad entre la anc&ura
y altura de la imagen% +sto exige que el control Pictureo+ se redimensione al tama0o del
rea de cliente de la ventana y que propiedad Si7e#ode del Pictureo+ tenga el valor
=oom% (a propiedad 6utoScrollPo!ition del panel se utiliza para a'ustar la posici-n del
control contenido (Pictureo+) en el control desplaza$le% Deg#n ;< expuesto, a0ada el
contro lador de esta orden y edtelo como se muestra a continuaci-n)
pri%ate %oi& <pciones@a$A(usta&o)Clic*(o'(ect sen&er, +%entArgs e)
,
i= (ciC$agen. C$age == null) return;
ciC$agen.1i&th = Panell.1i&th;
ciC$agen.:eight = Panell.:eight;
Panel1.Auto"crollPosition = new Point(<. <);
ciC$agen."ize8o&e = PictureBo."ize8o&e.Roo$;
-
(a orden :ama>o real tiene que presentar la imagen &aciendo que su tama>o sea el
real, ;< que se consigue asignando el valor )uto#ize a la propiedad Si7e#ode del
Pictureo+% Deg#n lo expuesto, a0ada el controlador de esta orden y edtelo como se indica
a continuaci-n)
pri%ate %oi& <pciones@a$9eal)Clic*(o'(ect sen&ero +%entArgs e)
,
i= (ciC$agen. C$age == null) return;
ciC$agen."ize8o&e = PictureBo."ize8o&e.Auto"ize;
-
(as -rdenes 8cercar y 8le'ar tienen que aumentar y disminuir, respectivamente, la
anc&ura y la altura de la ca'a de imagen, cilmagen, en la misma proporci-n y, a continuaci-n,
a'ustar la imagen al nuevo tama0o, lo que se consigue asignadoo el valor #tretchlma!e a la
propiedad Si7e#ode del Pictureo+% Deg#n lo expuesto, a0ada los controladores de estas
-rdenes y edtelos como se indica a continuaci-n)
pri%ate %oi& <pcionesAcercar)Clic* (o'(ect sen&er, +%entArgs e)
,
i= (ciC$agen.C$age == null) return;
229elaciNn ancho2alto &e la i$agen
&ou'le * = (&ou'le)ciC$agen.C$age.1ith 2 ciC$agen.C$age.:eight;
22Para una i$agen proporcional &e'e cu$plirse Hue0
22 ciC$agen.1ith 2 ciC$agen.:eight sea igual a *
int nue%oAncho = Concert.@oCnt52(ciC$agen.1ith T 1.2D);
ciC$agen.1i&th = nue%oAncho;
ciC$agen.:eight = Con%ert.@oCnt52(nue%oAncho 2 *);
ciC$agen."ize8o&e = PictureBo."ize8o&e."tretchC$age;
-
pria%ete %oi& <pcionesAle(ar)Clic* (<'(ect sen&er, +%entArgs e)
,
i= (ciC$agen.C$age == null) return;
229elaciNn ancho2alto &e la i$agen
&ou'le * = (&ou'le)ciC$agen.C$age.1i&th 2 ciC$agen.C$age.:eight;
22Para una i$agen proporcional &e'e cu$plirse Hue0
22 ciC$agen.1i&th 2 ciC$agen.:eight sea igual a *
int nue%oAncho = Con%ert.toCnt52(ciC$agen.1i&th 2 1.2D);
ciC$agen.1i&th = nue%oAncho;
ciC$agen.:eight = Con%ert.@<Cnt5(nue%oAncho2 *);
ciC$agen."ize8o&e = PictureBo."ize8o&e."trechC$age;
-
(a orden Girar ?-@ tiene que rotar la imagen I< grados en el sentido de las agu'as del
relo'% +ste proceso requiere permutar los valores de la anc&ura y de la altura de la ca'a de
imagen y llamar a su m.todo Rotate%lip con el argumento ;otate?-Flipone% 8 continuaci-n
&ay que invocar al m.todo Invalidate del Pictu reo+ para que se repinte y muestre los
cam$ios% Deg#n lo expuesto, a0ada el controlador de esta orden y edtelo como se indica a
continuaci-n)
pri%ate %oi& <pcionesGirar60)Clic*(o'(ect sen&ero +%entArgs e)
,
i= (ci C$agen. C$age == null) return;
int . = ciC$agen.1i&th;
ciC$agen.1i&th = ciC$agen.:eight;
ciC$age n.:eight = U;
ciC$age n.C$age . 9otate/lip(9otate/lip@#pe . 9otate60/lip4one);
ciC$age n.Cn%ali&ate() ;
-
Interca'biar i';gene! a trav>! del portapapele!
Luc&as aplicaciones utilizan el portapapeles (clipbaord) como repositorio temporal para los
datos de diferentes tipos (texto, imgenes, etc%)% Por e'emplo, en el captulo > lo utilizamos en
la aplicaci-n +ditor para dotarla de las operaciones cortar, copiar y pegar% +n una aplicaci-n
Windows, el acceso al portapapeles y el almacenamiento de datos en .l es posi$le mediante
el uso de los m.todos SetDataObject que almacena los datos en el portapapeles y
GetDataObject que recupera los datos del portapapeles utilizando la interfaz IDataObject% +l
m.todo SetDataObject funciona de forma que, ms adelante, se pueden recuperar los datos
del portapapeles en diversos formatos % +stos m.todos pertenecen a la clase Clipboard del
espacio de nom$res Sy!te'( 5indo)!(%or'!%
(a clase Clipboard proporciona el acceso al portapapeles y el almacenamiento de
imgenes en .l es posi$le mediante el uso de los m.todos SetI'age que almacena la
imagen en el portapapeles y GetI'age que recupera la imagen de portapapeles% Para
determinar si el formato de los datos se corresponde con el de una imagen, utilizaremos el
m.todo Contain!I'age% Por e'emplo)
i= (Clip'oar& . ContainsC$age())
,
$apaeBits = (Bit$ap)Clip'oar&.GetC$age();
Clip'oar& . Clear();
-
Deg#n ;< expuesto, escri$a el controlador del evento Clic1 de la orden ,op iar como
se indica a continuaci-n)
pri%ate %oi& <peionesCopiar)Clie*(o'(eet sen&ero +%entArgs e)
,
i= (ei C$agen. C$age == null) return;
Clip'oar&."etC$age(eiC$agen.C$age);
-
7inalmente, a0ada el controlador de la orden )cerca de %%%, del men# )'uda para que
muestre un dilogo con los cr.ditos de la aplicaci-n%
pri%ate %oi& A#u&aAeereae)Clie*(o'(eet sen&ero +%entArgs e)
,
"tring $ensa(e = >7isor &e i$Egenes. 7ersiNn 1 . 1> A
+n%iron$ent.4ew!ine A >Cop#right (e) /eo. Wa%ier Ce'allos, 200M[;
8essageBo.."how(8ensa(e, \Acerca &e 7isor &e C$agenes[);
-
Puede utilizar una ca'a de dilogo predefinida como la que muestra el m.todo anterior
o una ca'a de dilogo personalizada como la que muestra el m.todo siguiente)
pri%ate %oi& A#u&aAcercae)Clic* (o'(ect sen&er, +%entArgs e)
,
(new Acercae())."howialog();
-
Para a0adir este formulario a la aplicaci-n, dir'ase al explorador de soluciones, &aga
clic con el $ot-n secundario del rat-n so$re el nom$re del proyecto, seleccione )!re!ar A
Formulario Bindo7s A )cerca de( 8sgnele el nom$re )cercaDe% (os datos que visualiza
este formulario en sus etiquetas son proporcionados por el fic&ero )ssembl'Info(cs del
proyecto% Ko o$stante, puede editarlos y adaptarlos a sus requerimientos% Para ello, &aga clic
con el $ot-n secundario del rat-n so$re el nom$re del proyecto, seleccione Propiedades A
)plicaci&n A Informaci&n de ensamblado, y a0ada la informaci-n que desee en el dilogo que
se visualiza%
C6#I6R 06 %OR#6 DE0 P.=,ERO DE0 R6,?=
Para informar al usuario de la operaci-n que realizar el rat-n, se utilizan distintas imgenes
del puntero del rat-n, tam$i.n llamadas cursores% Por e'emplo, al editar o seleccionar texto,
suele mostrarse un cursor vertical (Cur!or!(Iean) y para informar al usuario de que se est
e'ecutando un proceso, se utiliza un relo' de arena (Cur!or!(5aitCur!or)% +sta imagen est
definida por un o$'eto de la clase Cur!or% 8s mismo, la clase ,ursors proporciona varios
cursores predefinidos%
Por otra parte, todos los controles que se derivan de la clase Control tienen una
propiedad Cur!or que &ace referencia a la imagen que muestra el puntero del rat-n cuando
est dentro de los lmites del control (la clase %or' tam$i.n se deriva, indirectamente, de la
clase Control9( Para cam$iarlo, seleccione el control, o el formulario, y asigne a su propiedad
Control la forma deseada del cursor% +l c-digo que se genera tras una acci-n de este tipo es
anlogo al siguiente (vea el e'ercicio Fta$lero de di$u'oF en el apartado de Cjercicios
resueltos)D
this.Panel .Cursor = "#ste$.1in&ows./or$s.Cursors.Cross
8lternativamente, puede mostrar cursores personalizados% Para ello, a0ada al
proyecto un nuevo elemento de tipo Farc&ivo de cursorF (fic&ero (cur)< di$u'e la forma del
cursor y gurdelo% espu.s, seleccione este fic&ero en el explorador de soluciones, dir'ase a
la ventana de propiedades y eli'a Frecurso incrustadoF como acci-n de generaci-n%
7inalmente, a0ada una lnea de c-digo anloga a la siguiente en el lugar adecuado (por
e'emplo, en el mane'ador del evento 0oad del formulario, en el constructor de .ste, etc%)%
,uando compile la aplicaci-n, la opcion EresourceDfichero(cur incrustar el recurso
especificado en el fic&ero resultante%
this.Cursor = new Cursor(this.Get@#pe(), >Cursorl.cur>);
E-ERCICIOS RES.E0,OS
;% Eepresentaci-n de funciones% +n ocasiones necesitaremos representar funci-n o
con'untos de datos suministrados por el usuario% Por e'emplo, en la figura siguiente puede
o$servar la representaci-n de la funci-n) A"4@xsen(<%C^x)^sen(;< ?x)%
(a superficie de di$u'o es un control PictureBox (en el c-digo lo identificaremos por
ci7uncion), la calidad de grfico se puede elegir entre normal y alta, y la funci-n que se
di$u'a se muestra en una etiqueta en el fondo de la ventana% +l intervalo de la varia$le 2 en
el que se representa la funci-n viene dado por los varia$les especificados en las ca'as
etiquetadas con %Fn y %x( Puede ver el desarrollo de la aplicaci-n completa en la carpeta
,ap-.1;esueltos lFunciones del , que acompa0a al li$ro%
/$s.rvese el rango empleado en la figura anterior para representar la funci-n) valores de 2
entre S<,C@ y G,@<% Pero tam$i.n podramos &a$er elegido otro rango, por e'emplo, entre < y
=<<<% +sto nos lleva a pensar que si utilizramos como unidades pxeles muc&os grficos no
entraran en la superficie de di$u'o% +s posi$le especificar las coordenadas en otras unidades
y de'ar que la G!" las convierta en pixeles antes de di$u'ar* para ello tendremos que
especificar el factor de escala para los e'es : e 9%
7'ese en la superficie de di$u'o de la figura anterior% Presenta los e'es : e 9 de coordenadas
que definen el origen (<, < l-gico% ,onocemos los valores mnimo y mximo de : (:min y
:max) y podemos calcular los valores mnimo y mximo de 9 (9min e 9max))
O$in = 7alor/uncion( U$in );
O$a. = 7alor/uncion( U$in );
=or (t = U$in; t S= U$a.; t A= (U$a. ] U$in) 2 (ci/uncion.1i&th ] 5))
,
%al = 7alor/uncion (t);
O$a. = 8ath.8a.(%al, O$a.);
O$in = 8ath.8in(%al , O$in);
-
Di la curva se extiende verticalmente desde 9min a 9max y la superficie de di$u'o de la
ci7uncion%Widt& S @ pxeles (S@ para evitar di$u'ar so$re el $orde), &ay que escalar el grfico
para que llene esta superficie% +ste factor de escala permitir convertir las unidades del e'e :
y del e'e 9 en pxeles)
matriz R new Latrix() *
matriz%Dcale(((ci7uncion% W idt& S @) ? (:max S :min)),
S(ci7uncion%Jeig &t S @) ? (9max S 9min))*
+l escalado iguala las superficies l-gica (delimitada por los valores : e 9 mximos y mnimos
de la funci-n) y fsica (tama0o de ci7uncion)% +l signo menos del factor de escala de 9 &ace
que los valores en este e'e crezcan &acia arri$a%
+l origen (<, <) fsico est situado en la esquina superior izquierda del control, y el origen (<,
<) l-gico est en otra posici-n dentro de la superficie de di$u'o% (a coordenada fsica <,C@
de$e corresponderse con la coordenada l-gica x cero% +sto es, la coordenada l-gica x cero
ser transformada, mediante una transformaci-n de desplazamiento, en el pxel
correspondiente a la coordenada fsica x <,C@)
coordenada l&!ica x 5 -<G" 6 coordenada fFsica x
Deg#n lo expuesto, la transformaci-n de desplazamiento en: es S(:min), esto es
S (S <,C@) R <,C@, que coincide con elS(:min)% Para el e'e vertical &aramos un razonamiento
anlogo, llegando a la conclusi-n de que la transformaci-n de desplazamiento en 9 es _
(9max)%
$atiz.@ranslate(PU$in. PO$a.)
,om$inemos a&ora las dos transformaciones% Para el e'emplo concreto so$re el que
estamos tra$a'ando, (:max S :min) R (G,@ S (S <,C@)) R A,;@% M,-mo se traducirn, por
e'emplo, las coordenadas l-gicas x de los extremos del e'e :l +sto es, :min y :max%
(P0 .E5 A 0,E5) . (ci/uncion.1i&th P 5) 2 M.1 5 = 0
(?.5 A 0.E5) . (ci/uncion.1i& t h P 5) 2M .1 5 = (ci/uncion .1i&th P 5)
+l resultado es el esperado) el pxel con la coordenada fsica x cero y el pixel con la
coordenada fsica x anc&o de la superficie de di$u'o% /$s.rvese que la transformaci-n de
desplazamiento se aplica antes que la de escalado% De deduce entonces que la
trasformaci-n total vendr dada por las siguientes operaciones)
$atriz."cale(((ci/uncion.1i&th P 5) 2 (U$a. P U$in)) ,
P(ci/uncion.:eight P 5) 2 (O$a.P O$in));
$atriz.@ranslate(PU$in, PO$a.);
lo cual, podra especificarse tam$i.n as)
$atriz.@ranslate(PU$in. PO$a.);
$atriz."cale(((ci/uncion.1i&th P 5) 2 (U$a. P U )) ,
P(ci/uncion.:eight P 5) 2 (O$a. ] O$in) ,
8atri.<r&er. Appen&);
5na vez comprendido c-mo traducir los puntos de la funci-n a pxeles veamos el
c-digo% +n primer lugar calcularemos los valores mnimo y mximo de : (:min y :max) y
mnimo y mximo de 9 (9min e 9max)% /$s.rvese que los valores de la funci-n se calculan
para tantos puntos como pxeles &aya lo largo del e'e :* no tiene sentido calcular el valor de
la funci-n para ms puntos de los existentes% 8 continuaci-n, se esta$lecen las
transformaciones en el o$'eto matriz% espu.s, se construyen los trazados para los e'es y
para la funci-n% 9 finalmente, se di$u'an esos trazados aplicndoles la transformaci-n
definida por matriz (trans formaci-n local) para que las coordenadas universales (world) se
conviertan en coordenadas en pxeles%
pri%ate %oi&ci/uncion)Paint(o'(ect sen&er, Paint+%entArgs e)
,
Graphics g = e.Graphics;
g.Clear (ci/uncion.Bac*Color);
Joat t;
Joat U$in, U$a.;
Joat O$a., O$in;
U$in = Con%ert.@o"ingle (.tU8in.@e.t);
U$a.= Con%ert.@o"ingle (ctU8a..@e.t);
i= (U$in ^= U$a.)
,
8essageBo.."how (\U $a. tiene Hue ser $a#or Hue U $in[);
return;
-
Joat %al;
O$in = 7alor/uncion(U$in);
O$a. = 7alor/uncion (U$in);
22Calcular el %alor &e la =unciNn para ca&a pi.el en el e(e U
22O o'tener el %alor $3.i$o # $Kni$o
=or (t = U$in; t S= U$a.; t A=(U$a. ] U$in) 2 (ci/uncion.1i&th P 5))
,
%al = 7alor/uncion(t);
i=(Joat.CsCnInit#(%al) ZZ Joat.Cs4a4(%al))
,
8essageBo.."how (\4o se pue&e &i'u(ar la =unciNn en este
rango[);
return;
-
O$a. = 8ath.8a.(%al, O$a.);
O$in = 8ath.8in (%al , O$in);
-
22$atriz %ale inicial$ente0 1 0 0 1 0 0
$atriz = new 8atri.( );
22 "cale $o&iIca los %a l ores pri$ero # cuarto
$atriz."cale(((ci/uncion.1i&th P 5) C (U$a. ] U$in)), P
(ci/uncion . :eight P 5) C (O$a. P O$in));
22 @ranslate $o&iIca los %alores Huinto # se.to
$atriz.@ranslate(PU$in. PO$a.);
22@raza&os para los e(es
GraphicsPath +(eU = new GraphicsPath();
GraphicsPath +(eO = new GraphicsPath();
+(eU.A&&!ine(new Point/(U$in, 0). new Point/(U$a.. 0)) ;
+(eO.A&&!ine(new Point/(0 , O$a.). new Point/(0,O$in));
22 @raza&o para la =unciNn
Joat UAnterior, OAnterior;
Joat U, O;
22 Ca&a seg$ento en el traza&o %a &es&e (UAnterior , OAnterior) a (U, O)
GraphicsPath /unciNn = new GraphicsPath();
Pen l3piz = new Pen(Color . Blac*, 1);
22 Punto inicial
UAnterior = U$in;
OAnterior = 7alor/uncion(U$in);
22 "eg$entos Hue =or$an el traza&o &e la =unciNn
=or (t = U$in; t S= U$a.; t A= (U$a. P U$in) 2 (ci/uncion.1i&th P 5))
,
U= t;
O = 7alor/uncion(t);
/unciNn.A&&!ine(UAnterior, OAnterior, U, O);
Uanterior = U;
OAnterior = O;
-
22 +sta'lecer la cali&a& con la Hue se &i'u(ar3
g."$oothing8o&e = cali&a&;
22 i'u(ar to&o aplican&o trans=or$aciones locales
+(eU .@rans=or$($atriz) ;
g.rawPath(l3piz , +(eU); 22 +(e U
+(eO.@rans=or$C$atriz) ;
g.rawPath(l3piz , +(eO); 22 +(e O
l3piz.Color = Color . Blue ;
/unciNn.@rans=or$($atriz); 22/unciNn
g.rawPath(l3piz, /unciNn);
-
Uamos a introducir en la aplicaci-n una lnea vertical desplaza$le a lo largo del e'e :,
que act#e como un cursor para seleccionar un punto del cual deseamos conocer sus
coordenadas% +l resultado puede verse en la figura mostrada un poco ms adelante%
(as coordenadas del punto seleccionado se visualizarn cada una de ellas en una ca'a de
texto% /$serve en la figura la ca'a de grupo Punto%
+l pro$lema planteado se resuelve utilizando los eventos del rat-n) #o u!e#ove y
#ou!e.p%
+l pro$lema de pintar una lnea vertical desplaza$le a lo largo del e'e : esta resuelto
de forma aislada en la carpeta ,ap<A; `Eesueltos`+ventosEaton del , que acompa0a al
li$ro% 8 continuaci-n explicamos c-mo incorporar esta t.cnica a la aplicaci-n que estamos
desarrollando%
+l cursor se pintar al &acer clic y mover el rat-n con el $ot-n izquierdo pulsado &acia
la derec&a o &acia la izquierda en la superficie de di$u'o% Deg#n esto, el controlador del
evento #ou!e#ove tiene que almacenar en los atri$utos x; , y; , x4 e y 4 de la clase 7orrnl
las coordenadas del cursor que pintar el m.todo ci7uncionaPaint, s-lo si el $ot-n izquierdo
del rat-n est pulsado% Para e'ecutar el m.todo ci7uncionaPaint, ci7uncionaLouseLove
invocar al m.todo Invalidate(
pri%ate %oi& ci/uncion)8ouse8o%e(o'(ect sen&ero 8ouse+%entArgs e)
,
i= (e . Button == "#ste$ . 1in&ows./or$s.8ouseButtons . !e=t)
,
'otonPulsa&o = true;
22 Coor&ena&as &el cursor a &i'u(ar
.1 = e.U;
#1 = 0;
.2 = e.U;
#2 = ci/uncion.:eight;
ci/uncion .Cn%ali&ate();
-
-
+l controlador del evento #ou!e.p se e'ecutar al soltar el $ot-n del rat-n y tiene
como misi-n $orrar el #ltimo cursor pintado as como el contenido de las ca'as de texto
etiquetadas con : e 9%
pri%ate %oi& ci/uncion)8ouseVp(o'(ect sen&ero 8ouse+%entArgs e)
,
'otonPulsa&o = =alse ;
ci/uncion .ln%ali&ate(); 22 'orrar el cursor
ctCoor&U.@e.t = \ [;
ctCoor&O .@e.t = \ [;
-

También podría gustarte