Nunca he sentido la tentacin de convertirme en programador de C++, ya que soy demasiado perezoso para trabajar tanto. Sin embargo, debo admitir que envidiaba a los programadores de C++ su capacidad para escribir controles visuales. Los controles en Visual Basic 6.0 y versiones anteriores se limitaban a controles compuestos (controles formados por otros) denominados UserControls. Escribir un control que tuviera su propia representacin visual en la pantalla en Visual Basic 6.0 era una tarea entre difcil e imposible. La buena noticia es que ahora Visual Basic .NET permite escribir todo tipo de controles visuales. An dispone de UserControls compuestos y tambin puede heredar de un control existente, como TextBox, y ampliarlo con nuevas capacidades. Es ms, puede escribir un control visual desde cero que presente su propia interfaz. En este artculo, har una demostracin de esta capacidad mediante la creacin de un control visual completo desde cero. El control es un semforo, es decir, un rectngulo con crculos en rojo, amarillo y verde. En la figura 1 se muestra la apariencia del control con cada una de las luces encendidas y con el color de fondo del control establecido en el color del sistema ControlDark.
Figura 1. Formulario con tres controles TrafficLight, cada uno con una luz diferente encendida. Lo llamaremos control TrafficLight y podr cambiar la luz activa, mediante cdigo o mediante clics por parte del usuario. Puesto que TrafficLight es un control de Windows Forms visual, heredar de la clase Control en el espacio de nombres System.Windows.Forms. Esto nos proporcionar gran cantidad de propiedades, mtodos y eventos predefinidos. Entre ellos, se incluyen propiedades para el control de la apariencia, como ForeColor, BackColor, Size yLocation, y eventos, como MouseOver y Click. Puede consultar la documentacin de .NET para obtener una lista completa de los miembros de la clase Control. La luz tambin necesitar las siguientes propiedades y eventos especiales: Propiedad Status Determina de qu color es la luz activada. Debe ser uno de los tres siguientes tipos de valores enumerados: StatusRed: la luz roja est activada. StatusYellow: la luz amarilla est activada. StatusGreen: la luz verde est activada. Propiedad BorderWidth La anchura del dibujo de borde que rodea el semforo. Evento StatusChanged Se desencadena cuando la propiedad Status cambia a un valor distinto, mediante cdigo o clics por parte del usuario en una luz diferente. Puesto que estos miembros no estn en la clase base Control, ser necesario incluir el cdigo completo para controlarlos. Tambin necesitaremos el cdigo para dibujar el semforo en la pantalla mediante el trazado del borde y los tres crculos con los colores adecuados. Finalmente, tendremos que controlar los clics realizados en un crculo para cambiar la luz activa y cambiar la propiedad Status cuando esto ocurra. Para que este ejemplo est tan listo para la produccin como sea posible, tambin incluiremos un cdigo para que el control funcione mejor con IDE de Visual Studio .NET. Le asignaremos un icono adecuado para el cuadro de herramientas e incluiremos la lgica para que las propiedades se integren correctamente con las ventanas Propiedades. Comencemos. Paso 1: creacin del tipo correcto de proyecto Para crear una biblioteca en la que almacenar controles de Windows Forms, inicie un nuevo proyecto en Visual Basic .NET y seleccione el tipo de proyecto Biblioteca de controles de Windows. D al proyecto el nombre MyControls. En el proyecto resultante se podrn almacenar varios controles de Windows Forms, cada uno en su propia clase. Sin embargo, slo vamos a crear un control dentro del proyecto. Paso 2: cambio de la clase base La clase creada en la biblioteca de controles tomar automticamente el nombre UserControl1 y, de forma predeterminada, heredar de la clase UserControl. Sera estupendo para crear un control compuesto, ya que bastara con empezar a arrastrar otros controles desde el cuadro de herramientas hasta la superficie de diseo. Sin embargo, como queremos crear nuestro propio control desde cero, tendremos que hacer algunos cambios. Cambie el nombre de la clase del control de UserControl1 a TrafficLight. A continuacin, cambie la lnea Inherits System.Windows.Forms.UserControl por esta otra: Inherits System.Windows.Forms.Control De esta forma, la clase ms genrica Control se convertir en la clase base. Observar que la superficie de diseo visual ya no estar disponible y que se sustituir por una superficie de diseo de componentes. Para mantener la coherencia del cdigo, cambie el nombre del archivo de cdigo UserControl1.vb por TrafficLight.vb. Para ello, en el Explorador de soluciones, haga clic con el botn secundario en el nombre del archivo de cdigo y seleccione Cambiar nombre. Tambin necesitaremos un par de lneas de cdigo en la parte superior del mdulo de clase. Estableceremos Option Strict en On e importaremos un espacio de nombres que contenga determinados atributos que utilizaremos ms tarde. A continuacin se muestran las dos lneas que se deben escribir al principio del cdigo: Option Strict On Imports System.ComponentModel Paso 3: implementacin de las propiedades y los eventos Para implementar la propiedad Status, primero tendremos que crear una enumeracin para los posibles valores de dicha propiedad. Inserte las lneas siguientes a continuacin de la lnea que comienza por Inherits: Public Enum TrafficLightStatus statusRed = 1 statusYellow = 2 statusGreen = 3 End Enum Esta enumeracin es pblica, es decir, los formularios que utilicen el control tendrn acceso a ella. A continuacin de esta lneas, agregue las tres lneas siguientes: Dim mStatus As TrafficLightStatus = TrafficLightStatus.statusGreen Dim msngBorderWidth As Single = 1.0! Public Event StatusChanged(ByVal NewStatus As TrafficLightStatus) Las dos variables de las dos primeras lneas proporcionan espacio para almacenar los valores de las propiedades Statusy BorderWidth y tambin establecen el valor predeterminado para dichas propiedades. La variable utilizada para almacenar BorderWidth deber ser de tipo Single, ya que es el tipo necesario para la instruccin de grficos que dibujar el borde. El signo de exclamacin en el valor predeterminado tambin indica que es de tipo Single. La ltima lnea de este conjunto declara el evento StatusChanged. Introduzcamos ahora el cdigo para la propiedad BorderWidth. Inserte las lneas siguientes justo debajo de la seccin de cdigo etiquetada como Cdigo generado por el Diseador de Windows Forms : <DefaultValue(1.0!), _ Description("Width of the border around the traffic light")> _ Public Property BorderWidth() As Single Get Return msngBorderWidth End Get Set(ByVal Value As Single) If msngBorderWidth <> Value Then msngBorderWidth = Value Me.Invalidate() End If End Set End Property Las dos primeras lneas incluyen atributos con los que se consigue que la propiedad funcione correctamente con el IDE. El atributo DefaultValue permite restablecer el valor de la propiedad en su valor predeterminado en la ventanasPropiedades (posteriormente veremos cmo hacerlo). El atributo Description proporciona el texto que aparecer en la parte inferior de la ventana Propiedades al seleccionar la propiedad. El atributo DefaultValue tambin tiene otras importantes ventajas. Si ubica el control TrafficLight en un formulario y deja el valor de la propiedad BorderWidth con su valor predefinido, el diseador de formularios no generar ninguna lnea de cdigo para establecer el valor de la propiedad. De esta forma, se consigue que acte como otros controles de Windows Forms. Si examina el cdigo generado por el diseador para un control tpico como TextBox, ver que slo se incluyen lneas de cdigo para propiedades que no se establecen en sus valores predeterminados. Daremos a nuestro control TrafficLight esta misma capacidad. La clusula Property Get es simple. La clusula Property Set incluye una lgica que suele encontrarse en propiedades de controles visuales. Al establecer la propiedad, es importante que el control se vuelva a dibujar si el nuevo valor de la propiedad cambia la apariencia del control. Por tanto, la clusula de Set comprueba si el nuevo valor que se est pasando es diferente al valor existente en la propiedad. Si no es as, no se lleva a cabo ninguna accin. Si el nuevo valor es diferente, se acepta y, a continuacin, se obtiene acceso al mtodo Invalidate. Este mtodo indica que el rea visual del control es obsoleta y que se debe volver a dibujar el control. La propiedad Status debe establecerse de forma ligeramente diferente, ya que es un valor enumerado. El atributoDefaultValue no otorga a una propiedad enumerada la capacidad de restablecimiento automtico. En este caso,DefaultValue no indica al diseador cundo no debe incluir el cdigo que establece el valor de la propiedad. De esta forma, nuestra implementacin de la propiedad Status omite el atributo DefaultValue . A continuacin se muestra el cdigo de la propiedad Status: <Description("Status (color) of the traffic light")> _ Public Property Status() As TrafficLightStatus Get Status = mStatus End Get Set(ByVal Value As TrafficLightStatus) If mStatus <> Value Then mStatus = Value RaiseEvent StatusChanged(mStatus) Me.Invalidate() End If End Set End Property Este cdigo se asemeja bastante a la implementacin de la propiedad BorderWidth, aunque hemos agregado algo. Cuando se cambia la propiedad Status, se desencadena el evento StatusChanged adems de forzar que el control se vuelva a dibujar. Para controlar el restablecimiento automtico de la propiedad en la ventana Propiedades, necesitamos un mtodo especial. Como la propiedad se llama Status, el nombre del mtodo de restablecimiento debe ser ResetStatus. Este mtodo simplemente devuelve a la propiedad su valor predeterminado. ste es el cdigo: Public Sub ResetStatus() Me.Status = TrafficLightStatus.statusGreen End Sub Para avisar al diseador de cundo debe incluir una lnea de cdigo para establecer la propiedad Status, necesitamos incluir un mtodo denominado ShouldSerializeStatus. Este mtodo devuelve un valor booleano True cuando se necesita una lnea de cdigo para la propiedad y False cuando no es as. ste es el cdigo: Public Function ShouldSerializeStatus() As Boolean If mStatus = TrafficLightStatus.statusGreen Then Return False Else Return True End If End Function Paso 4: dibujo de la apariencia del control Para dar al control una representacin visual, es necesario incluir una lgica en el evento Paint. Dicha lgica se ejecutar cada vez que se tenga que actualizar la apariencia visual del control. En Windows Forms, la lgica de Paint utiliza clases en la parte de .NET denominada GDI+. Bsicamente, estas clases son contenedores de las funciones grficas de la API de Windows. En .NET, son ms fciles de usar que la API. Sin embargo, hay varios puntos que debera tener en cuenta para comprender su funcionamiento. En la API de Windows, las operaciones grficas necesitan un identificador de ventana, denominado a veces hWnd. En GDI+, este identificador se sustituye por el objeto Graphics, que al mismo tiempo representa el rea de dibujo y ofrece operaciones (mtodos) para realizar en dicha rea. Por ejemplo, con el objeto Graphics se pueden utilizar los siguientes mtodos para dibujar diversos elementos de la pantalla: DrawCurve DrawEllipse DrawLine DrawPolygon DrawRectangle DrawString FillEllipse FillPolygon Estos mtodos son muy fciles de entender y representan slo una muestra de los mtodos disponibles. Algunos mtodos ms complejos permiten, por ejemplo, girar objetos. Utilizaremos el mtodo DrawRectangle para dibujar el borde y el mtodo FillEllipse para dibujar los crculos de colores. La mayor parte de los mtodos de dibujo necesitan un objeto Pen o Brush. Un objeto Pen se utiliza para dibujar una lnea y determinar el color y grosor de sta. Un objeto Brush se usa para rellenar regiones y determinar el color utilizado en el relleno, as como otros efectos especiales como, por ejemplo, el relleno de la regin con un mapa de bits. Utilizaremos un efecto Brush especial para sombrear el color de las luces que no estn encendidas. A continuacin, se muestra el cdigo que supervisa el evento Paint del control: Protected Overrides Sub OnPaint(ByVal pe As _ System.Windows.Forms.PaintEventArgs) MyBase.OnPaint(pe)
Dim grfGraphics As System.Drawing.Graphics grfGraphics = pe.Graphics
' Dibujar primero tres crculos para las luces. ' Uno estar "encendido". Los dems estarn sombreados. DrawLight(TrafficLightStatus.statusGreen, grfGraphics) DrawLight(TrafficLightStatus.statusYellow, grfGraphics) DrawLight(TrafficLightStatus.statusRed, grfGraphics)
' Dibujar ahora el contorno del semforo. ' Se necesita un lpiz para dibujarlo. Ser negro. Dim penDrawingPen As New _ System.Drawing.Pen(System.Drawing.Color.Black, msngBorderWidth)
' Dibujar el contorno del semforo en el control. ' Definir primero el rectngulo que se va a dibujar. Dim rectBorder As System.Drawing.Rectangle
' Eliminar los objetos de dibujo penDrawingPen.Dispose() grfGraphics.Dispose()
End Sub En primer lugar, se otorga a la clase base la capacidad de pintar y bsicamente pintar el fondo con el color correspondiente del control. A continuacin, el objeto Graphics del control se obtiene de los argumentos del evento. Posteriormente, se utiliza una funcin para dibujar cada uno de los tres crculos. Ms adelante trataremos esta funcin. Observe que debemos pasar a la funcin una referencia del objeto Graphics, junto con una indicacin del crculo que queremos dibujar (rojo, amarillo o verde). A continuacin est el cdigo para dibujar el contorno. Se declara un rectngulo con una posicin y tamao adecuados y, a continuacin, se pasan al mtodo DrawRectangle del objeto Graphics. Finalmente, los objetos del dibujo tienen activado el mtodo Dispose. Con GDI+, conviene eliminar los objetos de dibujo en cuanto haya terminado con ellos. De esta manera se limpian los recursos utilizados por el sistema operativo para dibujar. Si el control se va a utilizar en Windows 98 o Windows Millennium Edition, es muy importarte controlar los recursos grficos, ya que estos sistemas operativos tienen menos capacidad para dichos recursos. A continuacin se muestra la funcin que dibuja los crculos: Private Sub DrawLight(ByVal LightToDraw As TrafficLightStatus, _ ByVal grfGraphics As Graphics)
Dim nCircleX As Integer Dim nCircleY As Integer Dim nCircleDiameter As Integer Dim nCircleColor As Color
' Buscar la coordenada X y el dimetro de todos los crculos nCircleX = CInt(Me.Size.Width * 0.02) nCircleDiameter = CInt(Me.Size.Width * 0.96) Select Case LightToDraw Case TrafficLightStatus.statusRed If LightToDraw = Me.Status Then nCircleColor = Color.OrangeRed Else nCircleColor = Color.Maroon End If nCircleY = CInt(Me.Size.Height * 0.01) Case TrafficLightStatus.statusYellow If LightToDraw = Me.Status Then nCircleColor = Color.Yellow Else nCircleColor = Color.Tan End If nCircleY = CInt(Me.Size.Height * 0.34) Case TrafficLightStatus.statusGreen If LightToDraw = Me.Status Then nCircleColor = Color.LimeGreen Else nCircleColor = Color.ForestGreen End If nCircleY = CInt(Me.Size.Height * 0.67)
End Select Dim bshBrush As System.Drawing.Brush If LightToDraw = Me.Status Then
bshBrush = New SolidBrush(nCircleColor) Else bshBrush = New SolidBrush(Color.FromArgb(60, nCircleColor)) End If
' Dibujar el crculo para la luz de la seal grfGraphics.FillEllipse (bshBrush, nCircleX, nCircleY, nCircleDiameter, nCircleDiameter)
' Eliminar el pincel bshBrush.Dispose()
End Sub ste es el nico dibujo complejo del control. Se dibuja una elipse en GDI+ mediante la especificacin de las coordenadas X e Y de la esquina superior izquierda del rectngulo, donde se colocar la elipse, y la altura y anchura de dicho rectngulo. Se darn los nombres nCircleX y nCircleY a las coordenadas X e Y, respectivamente. Puesto que estamos dibujando un crculo, la altura y la anchura del rectngulo sern la misma y la variable nCircleDiameter se utilizar para incluir dicho valor. nCircleX se establece para que se site justo dentro del control (la anchura del control multiplicada por 0,02). La variable nCircleY depende de la luz que se est dibujando y se establece para que se site cerca de la parte superior del control (para la luz roja), a un tercio (para la luz amarilla) o aproximadamente a dos tercios (para la luz verde). El dimetro, nCircleDiameter, se establece al 96% de la anchura del control. Lo nico que falta para dibujar una elipse rellena es seleccionar el color que deseemos utilizar. Determinaremos el color en funcin de (1) la luz que estemos dibujando y (2) si la luz que estamos dibujando est encendida. Los colores de la luz activa deben tener ms brillo que los de la luz inactiva. El color se utiliza para crear un pincel para el dibujo. Si la luz que se est dibujando est activa, el color se utilizar tal cual. Sin embargo, si la luz est inactiva, se utilizar otra forma para crear una instancia del pincel. A continuacin se muestra la lnea de cdigo para un pincel de luz inactiva: bshBrush = New SolidBrush(Color.FromArgb(60, nCircleColor)) ste no es uno de los mejores nombres de mtodos dados en .NET, pero el mtodo FromArgB crea un pincel que sombrea el color mediante su combinacin con el color de fondo. El nmero utilizado como primer argumento est comprendido entre 0 y 255 y, cuanto menor sea, ms se fundir con el fondo. Vamos a usar un valor de 60, que atenuar considerablemente el color de la luz inactiva. Puede probar con valores diferentes para este argumento (o convertirlo en propiedad configurable) para obtener distintos efectos. Finalmente, el mtodo DrawEllipse del objeto Graphics dibuja el crculo y se completa la funcin. Recuerde que se llama a la funcin tres veces, una para cada crculo. Paso 5: cmo hacer que el control responda al usuario Para que el usuario pueda cambiar el color de la luz, se deben detectar los clics que realice. Para ello, existen varios medios, como cualquier programador con experiencia en Visual Basic sabe. Utilizaremos uno de los ms simples, que consiste en detectar el evento MouseUp. A continuacin se muestra el cdigo que detecta el clic del usuario y cambia la propiedad Status de forma adecuada: Private Sub TrafficLight_MouseUp(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs)_ Handles MyBase.MouseUp Dim nMidPointX As Integer = CInt(Me.Size.Width * 0.5) Dim nCircleRadius As Integer = nMidPointX If Distance(e.X, e.Y, nMidPointX, CInt(Me.Size.Height / 6)) _ < nCircleRadius Then Me.Status = TrafficLightStatus.statusRed Exit Sub End If If Distance(e.X, e.Y, nMidPointX, CInt(Me.Size.Height / 2)) _ < nCircleRadius Then Me.Status = TrafficLightStatus.statusYellow Exit Sub End If If Distance(e.X, e.Y, nMidPointX, CInt((5 * Me.Size.Height)/6))_ < nCircleRadius Then Me.Status = TrafficLightStatus.statusGreen End If
End Sub
Private Function Distance(ByVal X1 As Integer, _ ByVal Y1 As Integer, _ ByVal X2 As Integer, _ ByVal y2 As Integer) As Integer Return CInt(System.Math.Sqrt((X1 - X2) ^ 2 + (Y1 - y2) ^ 2)) End Function El control de eventos es bastante simple. Se comprueba la distancia entre la ubicacin del clic del mouse y el centro de cada crculo. Observe que los centros de los crculos estarn a 1/6, 1/2 y 5/6 de la extensin total del control, respectivamente. Si an no lo ve claro, dibjelo en un papel para comprobarlo. Si la distancia calculada es inferior al radio del crculo, se cambiar la propiedad Status. La funcin Distance calcula la distancia mediante una frmula algebraica que probablemente conocer. Observe que la funcin para calcular la raz cuadrada se toma del espacio de nombres System.Math, en el que se encuentran las funciones matemticas tpicas. Paso 6: limpieza Para que el control funcione sin problemas, se deben controlar un par de operaciones ms. Por ejemplo, es necesario volver a dibujar el control cuando cambie de tamao. Adems, para mantener las proporciones del control, se deben detectar los cambios en las propiedades que afectan al tamao y forzar que la anchura sea un tercio de la altura. A continuacin se muestran las rutinas para el control de eventos a cargo de estas tareas: Private Sub TrafficLight_Resize(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Resize Me.Invalidate() End Sub
Private Sub TrafficLight_Layout(ByVal sender As Object, _ ByVal e As System.Windows.Forms.LayoutEventArgs) _ Handles MyBase.Layout Select Case e.AffectedProperty Case "Bounds" Me.Width = CInt(Me.Height * 0.3333) Case Else ' No hacer nada End Select End Sub Finalmente, veamos el icono que se utilizar en el cuadro de herramientas. El control ya dispone de un icono predeterminado que se parece a un engranaje, pero utilizaremos otro que proporciona Visual Studio .NET que representa un semforo. El icono del cuadro de herramientas de un control se establece con un atributo de la clase denominada ToolboxBitmap. Inserte la siguiente lnea a continuacin de la lnea que comienza por Public Class : <ToolboxBitmap("C:\Archivos de programa\Microsoft Visual Studio .NET\Common7\Graphics\icons\Traffic\TRFFC09.ICO")> _ Nota Este cdigo debe incluirse en una sola lnea, se ha insertado un retorno de carro despus deStudio para facilitar su lectura. Cuando pegue este cdigo, asegrese de que se encuentra en una sola lnea, de que hay un nico espacio entre Studio y .NET y de que se ha eliminado el retorno de carro. De esta forma, se establecer el atributo en un icono ubicado en el directorio de Visual Studio para el atributo, suponiendo que ha instalado Visual Studio .NET en la ubicacin predeterminada. Si no es as, cambie la ruta al icono segn corresponda. Paso 7: generacin y prueba del control El control TrafficLight ya est terminado. Seleccione Generar | Generar MyControls para crear la biblioteca de controles terminada. Para probar el control, necesitaremos un proyecto de Windows Forms. Para ello, puede utilizar una solucin independiente, aunque es ms fcil hacerlo en la misma solucin utilizada para desarrollar el control. SeleccioneArchivo | Agregar proyecto | Nuevo proyecto en el men. Seleccione el tipo de proyecto Aplicacin para Windows e introduzca TestTrafficLight como nombre del proyecto. Haga clic en Aceptar para que la aplicacin para Windows realice la prueba. Para poder arrastrar un control TrafficLight a Form1 en blanco para la aplicacin de prueba, antes necesitar agregar el control TrafficLight al cuadro de herramientas. Haga clic con el botn secundario en la ficha de Windows Forms del cuadro de herramientas y seleccione Personalizar cuadro de herramientas. Seleccione la ficha Componentes de .NET Framework y, a continuacin, haga clic en el botn Examinar. Busque la ubicacin del proyecto MyControlsy, a continuacin, el directorio /bin del proyecto. Seleccione el componente MyControls.dll y haga clic en Aceptar. El cuadro de dilogo debera ser similar al que se muestra en la figura 2.
Figura 2. Seleccin del control TrafficLight en el cuadro de dilogo Personalizar cuadro de herramientas. Observe que junto al control TrafficLight hay una marca de verificacin. Haga clic en el botn Aceptar. El control TrafficLight aparecer ahora al final de la lista de controles de la ficha Windows Forms del cuadro de herramientas. En la figura 3 se muestra un cuadro de herramientas con el control TrafficLight situado al final.
Figura 3. Control TrafficLight al final de Toolbox Ahora, puede arrastrar un control TrafficLight a Form1 en blanco en TestTrafficLight. De forma predeterminada, su nombre ser TrafficLight1. Puede cambiar el tamao del control y establecer sus propiedades, incluida la propiedadStatus, que dispondr de un men desplegable con los tres posibles valores para dicha propiedad. Observe que a medida que cambia el tamao o las propiedades, el control se actualiza automticamente en el diseador. Para ver el restablecimiento de una propiedad en su valor predeterminado, cambie la propiedad Status a statusRed. A continuacin, haga clic con el botn secundario en la propiedad Status de la ventana Properties y seleccioneReset, como se muestra en la figura 4. La propiedad volver a cambiar a statusGreen. El truco del restablecimiento tambin funciona con la propiedad BorderWidth si se establece en un valor distinto de 1.
Figura 4. Opcin Restablecer para la propiedad Status en la ventana Propiedades. Observe la descripcin de la propiedad Status en la parte inferior de la ventana. Si lo desea, tambin puede insertar un evento StatusChanged para el control. A continuacin, podr ver el estado modificado con esta lnea de cdigo en dicho evento: MsgBox("New status is " & NewStatus.ToString) Para para realizar una prueba del control en plena accin, tendr que iniciar el proyecto TestTrafficLight. En este momento, no es el proyecto de inicio de la solucin, as que tendr que solucionarlo. En el Explorador de soluciones, haga clic con el botn secundario en el nombre Solution, en la primera fila. Seleccione Propiedades y, a continuacin, cambie la configuracin Proyecto de inicio nico de MyControls a TestTrafficLight. Haga clic enAceptar. Presione F5 para iniciar el proyecto. Aparecer el formulario con el control TrafficLight. Para probar el control, presione diferentes luces y observe cmo se encienden. Tambin puede realizar una prueba de la propiedadBorderWidth e intentar establecer la propiedad Status de la luz en el cdigo. Conclusin Hay que admitir que el control TrafficLight es simple, aunque conoc a un programador que lo necesit para un proyecto real. Sin embargo, muestra todos los principios necesarios para desarrollar controles ms sofisticados, entre los que se incluyen: La adicin de propiedades al control La posibilidad de que las propiedades se puedan coordinar con el IDE de Visual Studio mediante valores y descripciones predeterminados La insercin de una lgica en el evento Paint para dibujar el control El uso de GDI+ en la lgica de dibujo El establecimiento de un mapa de bits para que el control se muestre en el cuadro de herramientas La clave para crear controles ms sofisticados es familiarizarse con las capacidades de dibujo de GDI+. Si comprende cmo TrafficLight dibuja su contorno y los crculos de colores, es un buen punto de partida. La idea principal es que incluso los programadores perezosos como yo pueden crear controles de Windows Forms avanzados con Visual Basic .NET. About these ads