突出显示JTextPane中的当前行

我正在尝试超过2天来实现文本编辑器窗口的特定要求…不幸的是到目前为止没有成功:(

目标是获得一个文本编辑器窗口,该窗口将突出显示当前行,就像其他文本编辑器一样。 对于当前行,我指的是当前光标/插入符所在的行。

我已经找到了两种不同的方法,但不幸的是我无法采用它们,所以它们按预期工作。

第一种方法是覆盖DefaultHighlighter ( http://snippets.dzone.com/posts/show/6688 )。 在第二种方法中, HighlighterPainter将被覆盖( http://www.jroller.com/santhosh/date/20050622 )。

现在我正在尝试在我的项目中采用第一种方法,但正如我所说它不能按预期工作。

在这篇文章的最后,我发布了一个小样本应用程序来演示这个问题。

  • 如果我启动程序,则插入符号位于第一行的开头。 但是,该行未突出显示。
  • 现在我输入一些字符。 这些字符将突出显示,但只有那些字符不完整
  • 我点击Enter进入下一行。 第一行不再突出显示正确的内容。 第二行也没有突出显示,这是不正确的。 再次,当我输入一些字符时,那些将被突出但不是完整的行。
  • 当我现在将插入符号移回第一行时,通过向上键或鼠标单击,将突出显示完整的第一行,而不仅仅是现有的字符。 这是我从一开始就想要的行为。

我希望有人能告诉我这里我做错了什么……或者解释为什么根本无法解决这个问题。 如何实现线条突出显示的任何替代解决方案也非常感谢!

非常感谢Cheers 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  -1) { // Avoid allocing unless we need it. final Rectangle a = this.component.getBounds(); final Insets insets = this.component.getInsets(); ax = insets.left; ay = 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(); } } } 

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

我想这就是你要找的东西。 我拿了LinePainter类并将你的构造函数复制到main方法中,取出你的荧光笔部分并添加了一个new LinePainter(textPane); 奇迹般有效

下面是从当前行提取文本的代码。 您可以使用相同的逻辑来获取所需的索引并突出显示文本

  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; } 

我认为使用荧光笔可能很难实现 – 我不认为这是它们的设计目标。 您可能需要使用自定义绘制代码:

 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); } }