2010-08-20 10 views
6

Antes de que cualquiera sugiera HTML, explico más adelante por qué no es una opción aquí. Tengo una tabla que contiene una columna con celdas de texto. Necesito poder resaltar algo del texto en cada celda. Entonces, por ejemplo, si la celda contenía "cat foo dog" ... podría querer resaltar foo.¿Cómo resaltar parte de un JLabel?

Mi método actual es utilizar un TableCellRenderer personalizado que coloca html en un componente JLabel que se procesa y por un tiempo fue bueno. Luego noté que cuando el texto en la celda se hacía demasiado largo para caber en el ancho de la columna, simplemente truncaba el texto sin el "..." normal que normalmente sucede en este caso. Por lo tanto, los usuarios no sabían que había más texto que no estaban viendo. El otro problema era que si el texto original en sí contenía HTML, que en mi caso lo hace a veces, la celda no se procesaría correctamente. Sé que podría escapar del html pero aún tendría el problema previo.

Si utilizo un componente que no sea un jlabel, las celdas de mi mesa se ven extrañas. ¿Alguien tiene alguna sugerencia? Gracias

Respuesta

7

Bueno, aquí hay una solución.

En resumen, puede crear la subclase JLabel para resaltar manualmente. Reemplace el método paintComponent para hacer el dibujo real y use FontMetrics para calcular dónde debe dibujarse la región resaltada.

aquí es que la respuesta en absoluto detalle:

Básicamente, se puede hacer una subclase de JLabel que se pueden destacar cosas. Yo haría eso así; es posible que desee hacerlo de forma algo diferente:

Agregue un método que indique a la etiqueta qué parte resaltar. Esto podría ser algo como esto, suponiendo que sólo tiene una región resaltada:

public void highlightRegion(int start, int end) { 
    // Set some field to tell you where the highlight starts and ends... 
} 

Si necesita varias regiones, solo hay un ArrayList en lugar de un campo simple. Un método para deshighlighting probablemente sería útil también.

Ahora, debe anular el método paintComponent de JLabel. Aquí debe realizar varios pasos discretos, que puede organizar en diferentes métodos o algo. Para simplificar, lo pondré todo en el método de pintura.

@Override 
protected void paintComponent(Graphics g) { 
    ... 

En primer lugar, es necesario averiguar las dimensiones físicas de lo más destacado, lo que se puede hacer con la buena clase FontMetrics. Cree la clase FontMetrics para el Font que está utilizando.

FontMetrics metrics = new FontMetrics(getFont()); 

Ahora puede obtener toda la información que necesita para crear un rectángulo que será lo más destacado. Necesitarás la posición inicial, la altura y el ancho. Para conseguir esto, necesitará dos subcadenas de texto del JLabel 's de la siguiente manera:

String start = getText().substring(0, startOfHighlight); 
    String text = getText().substring(startOfHighlight, endOfHighlight); 
    //You may also need to account for some offsets here: 
    int startX = metrics.stringWidth(start); 
    int startY = 0; //You probably have some vertical offset to add here. 
    int length = metrics.stringWidth(text); 
    int height = metrics.getHeight(); 

Ahora se puede dibujar la región resaltada antes de dibujar el resto de la etiqueta:

g.fillRect(startX, startY, length, height); 
    super.paintComponent(g); 
} 

Por supuesto , si desea que el resaltado abarque varias filas, eso requerirá más trabajo.

Si te estabas preguntando, en realidad he escrito algo así antes. Por un capricho, decidí escribir mi propio componente de tipo de área de texto de JPanel, y esta era básicamente la forma en que manejaba el resaltado. Reinventar la rueda puede ser estúpido en un proyecto real, pero te enseña cosas al azar que pueden ser útiles ...

+0

Wow, gracias por su respuesta. Eso funciona casi perfectamente para JLabels. Sin embargo, encontré un problema. Si la etiqueta es setOpaque (verdadero) como se requiere en mi situación, hace que el resaltado no se muestre. Esto, creo, se produce llamando a super.paintComponent (g) después de hacer el dibujo personalizado. Traté de hacer el dibujo personalizado del resaltado primero, pero luego el rectángulo resaltado dibuja sobre el texto que se resaltará. Es una historia larga, pero para que las diapositivas de las tablas y algunas otras cosas, como el resaltado de filas, aparezcan en mi caso, debo establecer la etiqueta como opaca. Gracias por la respuesta. – startoftext

+0

Bueno, intente llamar primero a 'super.paintComponent (g)', y use 'g.setColor' para establecer el color en algo parcialmente transparente (por ejemplo,' new Color (0x33, 0x66, 0xFF, 0x66) 'es un bonito azul) antes de llamar a 'fillRect'. –

+0

Al final terminé básicamente re-implementando mi propio método de componente de pintura a algo que funcionó para mis propósitos. Y desistió de llamar al método de componente de pintura padre. Tu respuesta fue una muy buena y muy buena solución para responder el título de esta publicación, ya que se relaciona con una jlabel, así que la marcaré como aceptada. Gracias un montón Tikhon. – startoftext

2

Esa es una gran respuesta, y probablemente la mejor solución. Sin embargo, una alternativa que algunos podrían encontrar más simple es utilizar un JTextField en lugar de un JLabel para la representación, puede utilizar JTextFields destacando capacidades, es decir,

void highlightWhitespaceText(JTextField text) 
    { 
     text.setHighlighter(AbstractTableCellRenderer.defaultHighlighter); 
     try 
     { 
      Matcher m = AbstractTableCellRenderer.whitespaceStartPattern.matcher(text.getText()); 
      if (m.matches()) 
      { 
       text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter); 
      } 
      m = AbstractTableCellRenderer.whitespaceEndPattern.matcher(text.getText()); 
      if (m.matches()) 
      { 
       text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter); 
      } 
     } 
     catch (BadLocationException ble) 
     { 
      // 
     } 
    } 

Puede cambiar las propiedades de un JTextField para que se vea como un JLabel en otra saludos.

2

No se puede resistir a arrojar el mecanismo de decoración del renderizador SwingX al ring: su manera de resolver el requisito es implementar un Highlighter haciéndolo. Que de hecho ya está hecho (aunque aún no está oficialmente admitido) pero está oculto en el proyecto SwingLabs-Demos, llamado X/MatchingTextHighlighter (necesitaría ambos) y recientemente reparado para manejar íconos, RToL-ComponentOrientation, alineación, elipsis ..