2011-03-23 22 views
8

Estoy tratando durante más de 2 días para implementar un requisito específico para una ventana de editor de texto ... lamentablemente sin éxito hasta el momento :(Resaltar fila actual en JTextPane

El objetivo es conseguir una ventana de editor de texto que resaltará la fila actual, al igual que otros editores de texto. Con la fila actual me refiero a la fila donde actualmente se encuentra el cursor/cursor.

Ya encontré dos enfoques diferentes, pero desafortunadamente no puedo adoptarlos. funcionan como se esperaba.

El primer enfoque es sobrescribir el DefaultHighlighter (http://snippets.dzone.com/posts/show/6688). En el segundo enfoque, se sobrescribirá el HighlighterPainter en su lugar (http://www.jroller.com/santhosh/date/20050622).

En este momento estoy tratando de adoptar el primer enfoque en mi proyecto, pero como he dicho, no está funcionando como se desea.

Al final de esta publicación publicaré una pequeña aplicación de muestra que demuestra el problema.

  • Si comienzo el programa, el símbolo de intercalación se coloca al principio de la primera línea. Sin embargo, la línea no está resaltada.
  • Ahora escribo algunos caracteres. Esos caracteres se resaltarán pero solo esos caracteres no son la línea completa
  • Pulso enter para pasar a la siguiente línea. La primera línea ya no está resaltada, lo que es correcto. La segunda línea tampoco está resaltada, lo que no es correcto. Una vez más, cuando escribo algunos caracteres, estos serán resaltados pero no la fila completa.
  • Cuando vuelvo a mover la línea de intercalación a la primera línea, ya sea con la tecla de cursor hacia arriba o haciendo clic con el mouse, se resaltará la primera línea completa, no solo los caracteres existentes. Este es el comportamiento que quiero desde el principio.

Espero que alguien pueda decirme qué estoy haciendo mal aquí ... o explique por qué no es posible resolver ese problema en absoluto. ¡También se agradecen todas las soluciones alternativas sobre cómo podría realizar el resaltado de líneas!

Muchas gracias de antemano Saludos Preachie

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Insets; 
import java.awt.Rectangle; 

import javax.swing.JFrame; 
import javax.swing.JTextPane; 
import javax.swing.event.CaretEvent; 
import javax.swing.event.CaretListener; 
import javax.swing.text.DefaultHighlighter; 
import javax.swing.text.Highlighter; 
import javax.swing.text.JTextComponent; 

public class HighlightProblem extends JFrame { 
    private static final long serialVersionUID = 1L; 
    private final JTextPane textPane; 
    private final Highlighter.HighlightPainter cyanPainter; 

    public HighlightProblem() { 
     cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.CYAN); 

     textPane = new JTextPane(); 
     textPane.setPreferredSize(new Dimension(500, 300)); 
     textPane.setHighlighter(new LineHighlighter()); 
     textPane.addCaretListener(new CaretListener() { 
      @Override 
      public void caretUpdate(CaretEvent e) { 
       setHighlight(e); 
      } 
     }); 
     getContentPane().add(textPane); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     setVisible(true); 
    } 

    public static void main(String[] args) { 
     new HighlightProblem(); 
    } 

    public void setHighlight(CaretEvent e) { 
     textPane.getHighlighter().removeAllHighlights(); 
     int currentLine = getLineFromOffset(textPane, e.getDot()); 
     int startPos = getLineStartOffsetForLine(textPane, currentLine); 
     int endOffset = getLineEndOffsetForLine(textPane, currentLine); 

     try { 
      textPane.getHighlighter().addHighlight(startPos, endOffset, cyanPainter);   
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     textPane.repaint(); 
    } 

    public int getLineFromOffset(JTextComponent component, int offset) { 
     return component.getDocument().getDefaultRootElement().getElementIndex(offset); 
    } 

    public int getLineStartOffsetForLine(JTextComponent component, int line) { 
     return component.getDocument().getDefaultRootElement().getElement(line).getStartOffset(); 
    } 

    public int getLineEndOffsetForLine(JTextComponent component, int line) { 
     return component.getDocument().getDefaultRootElement().getElement(line).getEndOffset(); 
    } 

    public class LineHighlighter extends DefaultHighlighter { 
     private JTextComponent component; 

     @Override 
     public final void install(final JTextComponent c) { 
      super.install(c); 
      this.component = c; 
     } 

     @Override 
     public final void deinstall(final JTextComponent c) { 
      super.deinstall(c); 
      this.component = null; 
     } 

     @Override 
     public final void paint(final Graphics g) { 
      final Highlighter.Highlight[] highlights = getHighlights(); 
      final int len = highlights.length; 
      for (int i = 0; i < len; i++) { 
       Highlighter.Highlight info = highlights[i]; 
       if (info.getClass().getName().indexOf("LayeredHighlightInfo") > -1) { 
        // Avoid allocing unless we need it. 
        final Rectangle a = this.component.getBounds(); 
        final Insets insets = this.component.getInsets(); 
        a.x = insets.left; 
        a.y = insets.top; 
        // a.width -= insets.left + insets.right + 100; 
        a.height -= insets.top + insets.bottom; 
        final Highlighter.HighlightPainter p = info.getPainter(); 
        p.paint(g, info.getStartOffset(), info.getEndOffset(), a, this.component); 
       } 
      } 
     } 

     @Override 
     public void removeAllHighlights() { 
      textPane.repaint(0, 0, textPane.getWidth(), textPane.getHeight()); 
      super.removeAllHighlights(); 
     } 
    } 
} 

Respuesta

3

http://tips4java.wordpress.com/2008/10/29/line-painter/

creo que esto es lo que busca. Tomé esa clase LinePainter y copié el constructor de encima en un método principal, se llevó a cabo sus piezas de resaltado y añadió un new LinePainter(textPane); funciona como un encanto

+0

Muchas gracias ... se ve realmente como que está funcionando a las mil maravillas. – Preachie

+0

De nada. :) – spedsal

1

Creo que esto podría ser difícil de conseguir utilizando marcadores - Creo que no es para lo que fueron diseñados Es posible que deba hacerlo con un código de pintura personalizado:

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Rectangle; 

import javax.swing.JFrame; 
import javax.swing.JTextPane; 
import javax.swing.text.BadLocationException; 

public class HighlightLineTest { 
    private static class HighlightLineTextPane extends JTextPane { 
     public HighlightLineTextPane() { 
      // Has to be marked as transparent so the background is not replaced by 
      // super.paintComponent(g); 
      setOpaque(false); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      g.setColor(getBackground()); 
      g.fillRect(0, 0, getWidth(), getHeight()); 
      try { 
       Rectangle rect = modelToView(getCaretPosition()); 
       if (rect != null) { 
        g.setColor(Color.CYAN); 
        g.fillRect(0, rect.y, getWidth(), rect.height); 
       } 
      } catch (BadLocationException e) { 
      } 
      super.paintComponent(g); 
     } 

     @Override 
     public void repaint(long tm, int x, int y, int width, int height) { 
      // This forces repaints to repaint the entire TextPane. 
      super.repaint(tm, 0, 0, getWidth(), getHeight()); 
     } 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame("Highlight test"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new HighlightLineTextPane()); 
     frame.setBounds(100, 100, 300, 400); 
     frame.setVisible(true); 
    } 
} 
2

A continuación se muestra el código para extraer el texto de la línea actual. Puede utilizar misma lógica para obtener los índices requeridos y resaltar texto

private String getCurrentEditLine() { 
     int readBackChars = 100; 
     int caretPosition = scriptEditor.getCaretPosition(); 

     if (caretPosition == 0) { 
      return null; 
     } 

     StyledDocument doc = scriptEditor.getStyledDocument(); 

     int offset = caretPosition <= readBackChars ? 0 : caretPosition 
       - readBackChars; 

     String text = null; 
     try { 
      text = doc.getText(offset, caretPosition); 
     } catch (BadLocationException e) { 
     } 

     if (text != null) { 
      int idx = text.lastIndexOf("\n"); 
      if(idx != -1) { 
       return text.substring(idx); 
      }else { 
       return text; 
      } 
     } 

     return null; 
    } 
Cuestiones relacionadas