Trasteando con las JToolTip en Swing

23 02 2010

En esta entrada no voy a descubrir nada nuevo porque no soy un experto en Swing, pero son un par de detallitos que me han hecho perder algunos minutos.

La aplicación en la que estoy trabajando es un cliente Swing con componentes personalizados para construir una vista similar a diagramas de flujo. Estos componentes heredan de JPanel son más o menos complejos y sobrescriben los métodos de pintado como paintComponent. A su vez tienen componentes anidados y áreas ‘blancas’ que forman parte del componente Swing pero que en realidad para el usuario no forman parte del mismo. El siguiente diagrama lo ilustra un poco:

Mostrar el tooltip únicamente cuando el ratón está en determinadas partes del componente

Como sabemos la clase JComponent define el método setToolTipText(String tooltip) que permite establecer la tooltip, el ‘problema’ es que esta se establece para todo el componente. En mi ejemplo, yo sólo quiero que se muestre si el usuario posa el ratón en el diamante, ya que para él el resto del componente forma parte del fondo. Si no hacemos nada más, al poner el ratón en cualquier parte del componente se mostrará el tooltip.

La solución consiste en sobrescribir el método getToolTipText(MouseEvent event) para que devuelva null cuando las coordenadas del ratón (en el espacio de coordenadas del componente) están fuera del área para la que queremos mostrar el tooltip. El siguiendo snipet de código muestra la sobrescritura del método en mi componente personalizado: si estamos dentro del área definida por el rombo (calculado en un método auxiliar) entonces se muestra el tooltip establecido previamente con setToolTipText sino, devolvemos un null y por tanto no se renderizará el tooltip.

/**
* If the mouse is outside the diamond, don't show the tooltip.
*/
@Override
public String getToolTipText(MouseEvent event) {
    if (isInDiamond(event.getX(), event.getY())) {
        return getToolTipText();
    } else {
        return null;
    }
}

Tooltip multilínea

Aunque parezca sorprendente, la implementación por defecto del tooltip no soporta directamente multilíneas, así pues, si le pasamos un String que contenga retornos de carro en el método setToolTipText, éstos serán ignorados vilmente y se pintarán todas las líneas seguidas. Para solucionar ésto hay dos soluciones: una pesada y elegante y otra inmediata pero algo fea.

Empecemos por la segunda. Muchos componentes Swing tienen soporte para HTML. El tooltip también. Si asignamos un String que empiece por <html> el componente asumirá que le estamos pasando código HTML y lo renderizará como tal. El truco consiste pues, en sustituir todos los caracteres ‘\n’ por el String <br/>. Por ejemplo:

String strMultiLinea = ...
setToolTipText("<html>" + strMultiLinea.replaceAll("\n", "<br/>") + "</html>");

Rápido y funciona, pero es feo. La solución elegante consiste en implementar nuestro propio tooltip que soporte esta característica. Esto debemos hacerlo en dos pasos:

  1. Implementar nuestra clase tooltip personalizada heredando de javax.swing.JToolTip,
  2. Diciéndole al componente que debe usar nuestra propia implementación sobrescribiendo el método createToolTip para que devuelva una instancia de nuestra clase.
Anuncios

Acciones

Information

2 responses

23 02 2010
Maceda

Hola,
Buen post, pero a mí me ocurría una cosa cuando retornaba un NULL para el “getToolTipText”, que era ver renderizado un pequeño punto sobre la pantalla, ya que el ToolTipManager intentaba situar el tooltip (cuando no debería).
Al final tuvimos que desregistrar el componente del ToolTipManager durante el periodo en el que no debía mostrar información, para después volverlo a registrar.

Un saludo,

23 02 2010
Iván Párraga García

Hola,

He comprobado a ver si se producía el efecto que mencionas y aparentemente se comporta bien. De hecho, si está mostrando la tooltip y mueves el ratón fuera del área seleccionada, esta desaparece al momento.

Quizá este comportamiento no está especificado en la API (de hecho no lo he visto escrito en ningún sitio) y una versión anterior o diferente del JDK provoque el efecto que mencionas.

Merci por el comentario,

Iván

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s




A %d blogueros les gusta esto: