A continuación encontrarás traducido al Castellano el artículo escrito por Gabriel Ludosanu y publicado originalmente en el Blog de Xojo.
En la primera parte de este tutorial creamos un control básico personalizado utilizando para ello la clase DesktopCanvas, proporcionándole un aspecto y funcionalidad personalizados para la gestión de los eventos de ratón con una retroalimentación visual también personalizada, así como lanzar el evento Pressed cuando se pulsa.
En esta segunda parte mejoraremos nuestro CanvasButton añadiendo una mayor personalización con nuevas propiedades para:
- Definir los colores del botón para diferentes estados (por defecto, cuando el apuntador está sobre él, y pulsado).
- Ajustar el radio de las esquinas del botón.
- Implementar el estado de desactivado.
¡Comencemos!
Añadiendo nuevas propiedades de personalización
Precisamos añadir varias propiedades a nuestra clase CanvasButton con el objeto de referenciar colores personalizados para diferentes estados, el color del border, el color del texto, el radio de curvatura de las esquinas del botón y el estado de activado.
- En el Navegador de Proyecto, selecciona la clase CanvasButton.
- Dirígete a Insert > Property (o accede al menú contextual sobre la clase y selecciona la opción Add to “CanvasButton” > Property).
- Añade las siguientes propiedades con los nombres, tipos y valores por defecto indicados:
- Nombre: BackgroundColor; Tipo: Color; Valor por defecto: &c5e2d8b
- Nombre: HoverColor; Tipo: Color; Valor por defecto: &c729fcf
- Nombre: HighlightColor; Tipo: Color; Valor por defecto: &c628eff
- Nombre: BorderColor; Tipo: Color; Valor por defecto: &c525252
- Nombre: TextColor; Tipo: Color; Valor por defecto: &ceeeeee
- Nombre: CornerRadius; Tipo: Integer; Valor por defecto: 4
Estas propiedades contendrán los valores que determinan el aspecto y comportamiento del botón.
Actualizando los Manejadores de Evento para el estado Enabled
Hemos de modificar los manejadores de evento existentes (MouseDown, MouseEnter, MouseExit, MouseUp) para comprobar si el botón está activo antes de procesar cualquier acción del ratón.
Selecciona cada uno de los siguientes manejadores de evento en la clase CanvasButton y actualiza el código tal y como se muestra:
MouseDown(x As Integer, y As Integer) As Boolean
#Pragma unused x #Pragma unused y // Sólo se procesa si el botón está activado. If Enabled Then // Define el estado interno para indicar que se está pulsando el botón. IsPressed = True // Actualiza el control para que se muestre visualmente el estado de pulsado. Refresh(False) // Devuelve True para indicar que se ha manejado el evento. Return True Else // Si está desactivado, no manejamos el evento. Return False End If
MouseEnter()
// Sólo se procesa si el botón está activado. If Enabled Then // Define el estado interno para indicar que el apuntador está sobre el botón. IsHovered = True // Actualiza el control para mostrar visualmente el estado. Refresh(False) End If
MouseExit()
// Sólo se procesa si el botón está activado. If Enabled Then // Define el estado interno para indicar que el apuntador ya no está sobre el control. IsHovered = False // Actualiza el estado de pulsado si el apuntador deja de estar sobre el control mientras que se ha pulsado (previene clics accidentales). IsPressed = False // Actualiza el control para revertir su estado. Refresh(False) End If
MouseUp(x As Integer, y As Integer) As Boolean
#Pragma unused x #Pragma unused y // Sólo se procesa si el botón está activado. If Enabled Then // Comprueba si se ha pulsado el botón y el apuntador aun se encuentra sobre él. If IsPressed And IsHovered Then // Si es así, se ha hecho clic sobre el botón y se lanza el evento personalizado Pressed. RaiseEvent Pressed End If // Resetea el estado de pulsado independientemente de que el clic se haya realizado con éxito. IsPressed = False // Actualiza el control para revertir su estado de pulsado. Refresh(False) End If
En estos manejadores de evento actualizados hemos añadido un “If Enabled Then” al inicio. Si el botón no se encuentra activado, el código dentro del bloque no se ejecuta evitando que el botón reaccione a las interacciones con el apuntador. También hemos añadido #Pragma con los parámetros no utilizados x e y en los eventos MouseDown y MouseUp, dado que no se utilizan en el código, lo cual ayuda a evitar los Warning del compilador. En MouseExit hemos añadido IsPressed = False para asegurarnos de resetear el estado de pulsado en el caso de que el apuntador abandone el control mientras que se mantiene pulsado el botón del ratón.
Actualizando el Evento Paint para mejorar el aspecto
los cambios más significativos estarán en el evento Paint, donde utilizaremos las nuevas propiedades para dibujar el botón basándonos en su estado actual (activado/desactivado, si el apuntador está o no sobre el botón, y también si está o no pulsado).
Selecciona el manejador de evento Paint(g As Graphics, areas() As Rect) y sustituye su contenido con el siguiente código:
#Pragma unused areas // Utiliza la propiedad del radio de redondeo para las esquinas. Var currentCornerRadius As Integer = CornerRadius // Declara las variables para los colores utilizados en el dibujado. Var currentBgColor As Color Var currentBorderColor As Color Var currentTextColor As Color // Determina los colores basándose en el estado actual. If Enabled Then If IsPressed Then // Usa el color de destacado si está pulsado. currentBgColor = HighlightColor currentBorderColor = BorderColor currentTextColor = TextColor ElseIf IsHovered Then // Comprueba si está sobre el cursor sólo si no está pulsado // Usa el color hover si el apuntador está sobre el control. currentBgColor = HoverColor currentBorderColor = BorderColor currentTextColor = TextColor Else // Usa el color de fondo para el estado por defecto. currentBgColor = BackgroundColor currentBorderColor = BorderColor currentTextColor = TextColor End If Else // Usa los colores correspondientes del sistema o los grises estándar para el estado de desactivado. currentBgColor = Color.LightGray currentBorderColor = Color.Gray currentTextColor = Color.DisabledTextColor // usa el color de texto desactivado del sistema. End If // Define el color de dibujado y dibuja la forma de fondo con las esquinas redondeadas. g.DrawingColor = currentBgColor g.FillRoundRectangle(0, 0, g.Width, g.Height, currentCornerRadius, currentCornerRadius) // Define el color de dibujado y el tamaño de lápiz para el borde. g.DrawingColor = currentBorderColor g.PenSize = 2 // Dibuja la forma del borde justo dentro del rectángulo de fondo. g.DrawRoundRectangle(1, 1, g.Width-2, g.Height-2, currentCornerRadius, currentCornerRadius) // Activa el anti-aliasing para un dibujado suavizado del texto. g.AntiAliasMode = Graphics.AntiAliasModes.HighQuality g.AntiAliased = True // Calcula el ancho y altura para el texto del botón. Var tw As Double = g.TextWidth(ButtonText) Var th As Double = g.TextHeight // Calcula la posición X para centrar el texto horizontalmente. Var tx As Double = (g.Width - tw) / 2 // Calcula la posición Y para centrar verticalmente el texto, con un pequeño ajuste.. Var ty As Double = (g.Height + th) / 2 - 3 // Define el color de dibujado para el texto. g.DrawingColor = currentTextColor // Dibuja el texto del botón en la posición que se ha calculado.. g.DrawText(ButtonText, tx, ty)
Revisemos los cambios en el evento Paint:
- Ahora utilizamos la propiedad CornerRadius en vez de usar una constante estática para el dibujado de los bordes redondeados en los rectángulos.
- Hemos añadido un bloque If Enabled Then… Else.
- Dentro del bloque If Enabled Then, hemos añadido una estructura anidada If IsPressed Then… ElseIf IsHovered Then… Else. Esto determina el color currentBgColor:
- Si IsPressed es cierto, entonces currentBgColor se define a HighlightColor.
- Si IsPressed es falso, pero IsHovered es cierto, entonces currentBgColor se define a HoverColor.
- Si tanto IsPressed como IsHovered son falsos, entonces currentBgColor se define a BackgroundColor.
- Los valores de currentBorderColor y currentTextColor se ajustan directamente desde las propiedades BorderColor y TextColor cuando el botón está activado.
- Dentro del bloque Else (cuando Enabled es falso), definimos los colores a los valores de gris estándar (Color.LightGray para el fondo, Color.Gray para el borde, y Color.DiseabledTextColor para el texto) para dar así el aspecto de desactivado al botón.
- Por último, los comandos de dibujado utilizan estas variables currentBgColor, currentBorderColor, currentTextColor y currentCornerRadius.
Usando el Control personalizado mejorado
Ahora que nuestro CanvasButton tiene más opciones de personalización y soporta un estado de desactivado, veamos cómo utilizar estas características.
Si aún no tienes una instancia, arrastra la clase CanvasButton desde el Navegador de Proyecto sobre la ventana en el Editor de Diseño.
Ahora puedes acceder y definir las nuevas propiedades desde código. Por ejemplo, en el evento Opening del botón, puedes añadir las siguientes líneas:
// Personaliza los colores Me.BackgroundColor = Color.RGB(200, 50, 50) // Un tono de rojo Me.HoverColor = Color.RGB(255, 100, 100) // Un color rojo más claro para cuando el apuntador está sobre el control Me.HighlightColor = Color.RGB(150, 0, 0) // Un tono de rojo más oscuro para cuando se pulsa sobre el botón Me.BorderColor = Color.Black Me.TextColor = Color.White // Ajusta el radio de redondeo para el borde del contorno Me.CornerRadius = 10
Puedes experimentar con diferentes valores y ver cómo estos afectan al aspecto del botón. Para probar el estado de desactivado, puedes ajustar la propiedad Enabled a False.
Conclusión
Hemos llevado nuestro botón personalizado al siguiente nivel añadiendo más opciones de personalización para el color, así como un redondeo de contorno personalizado y un estado de desactivado.
Puedes descargar este proyecto desde GitHub desde este enlace.
¡Espero que hayas disfrutado creando tu propio control! Si bien ahora es mucho más flexible, probablemente también podríamos añadir otras capacidades, así que… ¡permanece atento!