Colaboraciones en el Guille

Componente SuperToolTip

[Modificación visual del componente ToolTip]

 

Fecha: 09/Jun/2006 (07/Jun/2006)
Autor: Omar Ulises Silva Domínguez

 


Introducción

El componente ToolTip representa una pequeña ventana emergente rectangular que muestra una breve descripción de la finalidad de un control cuando el usuario sitúa el puntero sobre el control [1]; para el usuario a veces esa breve descripción no es suficiente, debido a que le resulta muy escasa o confusa ocasionando que el usuario tenga que acceder a los documentos de la Ayuda con el fin de ampliar o comprender la finalidad del control.

El objetivo principal del componente SuperToolTip es la de proveer a los controles una descripción visualmente más rica que un ToolTip, de manera que es un término medio entre un ToolTip y la Ayuda.

Comparación del ToolTip contra el SuperToolTip
Comparación de un ToolTip con un SuperToolTip

Detrás de la idea del Super ToolTip

La idea del Super ToolTip no es mía, es un componente realizado por mí, con Visual Basic 2005 Express Edition y fue inspirado por un blog que leí en donde el autor hablaba acerca de la interfaz gráfica del Office 12.

SuperToolTip en Office 12
SuperToolTip en Office 12

Breve explicación de la clase ToolTip

La clase ToolTip para la versión 2.0 del .NET Framework trae nuevas propiedades, así como dos nuevos eventos: Draw y Popup.

El evento Popup sucede justo antes de que el ToolTip se muestre en pantalla, este evento es ideal para cambiar el tamaño del ToolTip antes de que se muestre.

El evento Draw se produce cuando se dibuja el ToolTip y la propiedad OwnerDraw se establece en True. En este evento se puede cambiar la apariencia del ToolTip.

La propiedad extensora ToolTip es utilizada para escribir el mensaje descriptivo que acompaña a cada control, sólo si esta propiedad es inicializada se mostrará la ventana emergente ToolTip. Este último punto es importante ya que el SuperToolTip usará esta propiedad para mostrarse.

El componente SuperToolTip

El SuperToolTip tiene todas las funcionalidades de un ToolTip, con algunas extras, por tanto es un componente que hereda de la clase ToolTip. Se agregó una nueva propiedad de tipo Boolean llamada IsSuperToolTip la cual indica si el SuperToolTip tendrá esta apariencia o será un ToolTip normal, por defecto esta propiedad es True, también se agregaron cinco propiedades extensoras:

SuperToolTipTitle. De tipo String, indica el titulo que tendrá el SuperToolTip.
SuperToolTipIcon. De tipo Image, indica una imagen que representa un icono en la esquina superior derecha.
SuperToolTipText. De tipo String, indica el texto descriptivo del SuperToolTip. Para que el SuperToolTip se muestre por lo menos esta propiedad debe estar inicializada.
SuperToolTipImage. De tipo Image, indica la imagen que amplia la descripción. Una imagen dice más que mil palabras.
SuperToolTipFooter. De tipo String, indica el pie del SuperToolTip.

Las propiedades extensoras anteriores son los elementos que conforman al SuperToolTip.

Elementos del SuperToolTip
Elementos del SuperToolTip

Aquí se muestra en resumen la clase SuperToolTip:

<ProvideProperty("SuperToolTipTitle", GetType(Control)), _
 ProvideProperty("SuperToolTipIcon", GetType(Control)), _
 ProvideProperty("SuperToolTipText", GetType(Control)), _
 ProvideProperty("SuperToolTipImage", GetType(Control)), _
 ProvideProperty("SuperToolTipFooter", GetType(Control))> _
Public Class SuperToolTip
    Inherits System.Windows.Forms.ToolTip

    ' Declaración de variables globales

    ' Hashtables para almacenar los valores de las propiedades
    ' extensoras en cada control
    Private superToolTipTitleValues As New Hashtable()
    Private superToolTipIconValues As New Hashtable()
    Private superToolTipTextValues As New Hashtable()
    Private superToolTipImageValues As New Hashtable()
    Private superToolTipFooterValues As New Hashtable()

    Private _isSuperToolTip As Boolean

    <Description("Indica si el ToolTip tomará la forma de un SuperToolTip"), _
     DefaultValue(True)> _
    Public Property IsSuperToolTip() As Boolean
        Get
            Return _isSuperToolTip
        End Get
        Set(ByVal value As Boolean)
            _isSuperToolTip = value
            If value Then
                OwnerDraw = True
            End If
        End Set
    End Property

    <DefaultValue(True)> _
    Public Shadows Property OwnerDraw() As Boolean
        Get
            Return MyBase.OwnerDraw
        End Get
        Set(ByVal value As Boolean)
            MyBase.OwnerDraw = value
            If Not value Then
                IsSuperToolTip = False
            End If
        End Set
    End Property

    ' Constructor, se inicializa IsSuperToolTip en True, que a su vez cambia OwnerDraw a
    ' True para permitir que se ejecute el evento Draw
    Public Sub New()
        IsSuperToolTip = True
    End Sub

    <Description("Determina el texto descriptivo que tendrá el SuperToolTip"), _
     DefaultValue(""), _
     Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", GetType(UITypeEditor))> _
    Public Function GetSuperToolTipText(ByVal control As Control) As String
        ..
    End Function

    Public Sub SetSuperToolTipText(ByVal control As Control, ByVal text As String)
        ..
    End Sub

    <Description("Determina el titulo que tendrá el SuperToolTip"), _
     DefaultValue("")> _
    Public Function GetSuperToolTipTitle(ByVal control As Control) As String
        ..
    End Function

    Public Sub SetSuperToolTipTitle(ByVal control As Control, ByVal title As String)
        ..
    End Sub

    <Description("Determina el icono que tendrá el SuperToolTip en la parte superior derecha"), _
     DefaultValue(GetType(Object), "")> _
    Public Function GetSuperToolTipIcon(ByVal control As Control) As Image
        ..
    End Function

    Public Sub SetSuperToolTipIcon(ByVal control As Control, ByVal icon As Image)
        ..
    End Sub

    <Description("Determina la imagen que tendrá el SuperToolTip"), _
     DefaultValue(GetType(Object), "")> _
    Public Function GetSuperToolTipImage(ByVal control As Control) As Image
        ..
    End Function

    Public Sub SetSuperToolTipImage(ByVal control As Control, ByVal image As Image)
        ..
    End Sub

    <Description("Determina el pie que tendrá el SuperToolTip"), _
     DefaultValue("")> _
    Public Function GetSuperToolTipFooter(ByVal control As Control) As String
        ..
    End Function

    Public Sub SetSuperToolTipFooter(ByVal control As Control, ByVal footer As String)
        ..
    End Sub

    Private Function ObtenerTemaActual() As String
        ' Esta función obtiene el tema de Windows XP
    End Function

    Private Sub SuperToolTip_Draw(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawToolTipEventArgs) Handles Me.Draw
        ' Todo lo relacionado al dibujo del SuperToolTip
    End Sub

    Private Sub SuperToolTip_Popup(ByVal sender As Object, ByVal e As System.Windows.Forms.PopupEventArgs) Handles Me.Popup
        ' Todo lo relacionado al calculo de posiciones de los elementos
        ' y tamaño del SuperToolTip
    End Sub

End Class

Nota: El código completo puede ser visto en el archivo zip que acompaña al artículo.

La clase SuperToolTip tiene implementado los eventos Popup y Draw. En el evento Popup se llevan a cabo los cálculos para ajustar el tamaño del SuperToolTip de acuerdo a las propiedades extensoras inicializadas y en el evento Draw se realiza la tarea de dibujar los elementos que conforman el SuperToolTip.

La propiedad IsSuperToolTip por defecto está en True, y esta ligada a la propiedad OwnerDraw, si la propiedad OwnerDraw se cambia a False también lo hará la propiedad IsSuperToolTip y si la propiedad IsSuperToolTip se cambia a True también lo hará la propiedad OwnerDraw, este comportamiento es debido a que OwnerDraw es la bandera que indica si se ejecuta o no el evento Draw y el usuario se confundiría si cambiase a False OwnerDraw e IsSuperToolTip se quedara en True y al ejecutar el programa se diera cuenta que el SuperToolTip se muestra como un ToolTip normal por que la implementación del evento Draw del componente no se ejecutaría.

Un ejemplo del uso de la propiedad IsSuperToolTip es en una aplicación en donde el usuario está en capacitación con un programa, el programador decide hacer uso del SuperToolTip con la propiedad IsSuperToolTip en True para que el usuario vea los mensajes descriptivos con más detalle y le ayuden en su capacitación, pero poco tiempo después el usuario ya sabe utilizar el programa, entonces con la propiedad IsSuperToolTip en False se deshabilitan los SuperToolTip de tal manera que solo aparezcan los ToolTips normales. Esto es usando una ventana de configuración en el programa en donde se habilita o deshabilita el uso de los SuperToolTips e internamente en la programación se hace uso de la propiedad IsSuperToolTip.

Truco

Cuando hice el análisis del componente, me di cuenta que el SuperToolTip no se iba a mostrar tan solo por llenar las propiedades extensoras arriba mencionadas y aunque el evento Draw estaba implementado, éste nunca iba a suceder si el SuperToolTip no se mostraba, entonces decidí realizar el siguiente truco, cuando el usuario inicializa la propiedad extensora SuperToolTipText en el método SetSuperToolTipText se inicializa la propiedad extensora ToolTip la cual se encarga de hacer lo necesario para que el ToolTip se muestre, esto solo lo hace si la propiedad extensora ToolTip no ha sido inicializada con anterioridad.

Public Sub SetSuperToolTipText(ByVal control As Control, ByVal text As String)
    If text Is Nothing Then
        text = ""
    End If
    If String.IsNullOrEmpty(text) Then
        superToolTipTextValues.Remove(control)
    Else
        If superToolTipTextValues.Contains(control) Then
            superToolTipTextValues(control) = text
        Else
            superToolTipTextValues.Add(control, text)
        End If
        ' Si la propiedad extensora ToolTip no tiene nada, se agrega el mismo texto
        ' de la propiedad extensora SuperToolTipText, ya que la propiedad ToolTip 
        ' es la que indica que el control tiene asociado un ToolTip
        If GetToolTip(control) = "" Then
            SetToolTip(control, text)
        End If
    End If
End Sub

Temas de Windows XP

Por último, el SuperToolTip tiene un detalle estético que le permite cambiar automáticamente el color de fondo de acuerdo al tema que tenga Windows XP. Este es el código del procedimiento que identifica el tema de Windows XP, basado en un código escrito en C# [3].

Private Function ObtenerTemaActual() As String
    Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\ThemeManager")
    If key IsNot Nothing Then
        If CBool(key.GetValue("ThemeActive")) Then
            Dim tema As String = CStr(key.GetValue("ColorName"))
            If tema IsNot Nothing Then
                Select Case tema
                    Case "Metallic"
                        Return "Plateado"
                    Case "NormalColor"
                        Return "Azul"
                    Case "HomeStead"
                        Return "Verde Olivo"
                End Select
            End If
        End If
    End If
    Return "Windows Clasico"
End Function

El mismo SuperToolTip con diferentes temas
El mismo SuperToolTip con diferentes temas de Windows XP

Nota: Aunque no lo he probado en otras versiones de Windows, en teoría el componente debería de funcionar pero se aplicaría el tema de Windows Clásico.

Limitaciones

El componente tiene algunas limitaciones, una de ellas es la orientación automática de la imagen descriptiva. La orientación de la imagen en el SuperToolTip depende del tamaño de la imagen, si la imagen es alta se mostrará verticalmente alineada a la izquierda, si la imagen es ancha se mostrará horizontalmente alineada a la parte superior.

SuperToolTip con diferentes alineaciones de imagen
Dos SuperToolTips con diferente orientación de imagen

El tamaño del SuperToolTip se calcula también de manera automática y depende del los elementos que vaya a contener el SuperToolTip.

El icono de la esquina superior derecha es de tipo Image y es preferible que sea un bitmap con fondo color magenta (#FF00FF) ya que este color está definido en la clase como color transparente.

Uso del componente SuperToolTip

El uso del SuperToolTip es exactamente igual a la de un ToolTip, el SuperToolTip agrega seis propiedades extensoras a todos los controles en un formulario, una propiedad que se heredó de la clase ToolTip y cinco nuevas, de las cinco nuevas, para mostrar el SuperToolTip sólo la propiedad SuperToolTipText es obligatoria, las demás son opcionales.

Propiedades extensoras del SuperToolTip
Las propiedades extensoras del SuoerToolTip

Conclusiones

El componente SuperToolTip es un ejemplo de cómo hacer componentes a partir de otros usando la herencia. Aunque tiene algunas limitaciones, es muy práctico, útil y fácil de usar. Espero les sea de ayuda el componente.

Nota: El archivo zip que acompaña al artículo tiene una solución con dos proyectos, uno es el componente SuperToolTip y el otro es un proyecto que prueba el uso del componente SuperToolTip.

Nota: La calidad de las imágenes se ha disminuido con el fin de agilizar la descarga de la página, es por eso que el degradado de los SuperToolTips se ve un poco mal.

Saludos desde México

Omar Ulises Silva Domínguez


Espacios de nombres usados en el código de este artículo:

Microsoft.Win32
System.ComponentModel
System.Windows.Forms
System.Drawing
System.Drawing.Design
System.Drawing.Drawing2D
System.Collections


Referencias

[1] Documentación de Microsoft .NET Framework SDK 2.0 - Acerca de la Clase ToolTip

[2] Jensen Harris: An Office User Interface Blog

[3] Code Project - Detecting XP Themes por Alastair Dallas


Fichero con el código de ejemplo: omarslvd_ComponenteSuperToolTip.zip - Tam. 66.8 KB

(MD5 checksum: [D6D8583D30891F45EE3E84C92AA6E97C])


ir al índice principal del Guille