我正在尝试超过2天来实现文本编辑器窗口的特定要求...遗憾的是到目前为止没有成功:(
目标是获得一个文本编辑器窗口,该窗口将突出显示当前行,就像其他文本编辑器一样。对于当前行,我指的是当前光标/插入符所在的行。
我已经找到了两种不同的方法,但不幸的是我无法采用它们,所以它们按预期工作。
第一种方法是覆盖DefaultHighlighter
(http://snippets.dzone.com/posts/show/6688)。
在第二种方法中,HighlighterPainter
将被覆盖(http://www.jroller.com/santhosh/date/20050622)。
现在我正在尝试在我的项目中采用第一种方法,但正如我所说,它没有按预期工作。
在这篇文章的最后,我发布了一个小样本应用程序来演示这个问题。
我希望任何人都可以告诉我这里我做错了什么......或解释为什么根本无法解决这个问题。如何实现线条突出显示的任何替代解决方案也受到高度赞赏!
提前多多感谢 干杯 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();
}
}
}
答案 0 :(得分:3)
http://tips4java.wordpress.com/2008/10/29/line-painter/
我认为这就是你要找的东西。我拿了那个LinePainter
类并将你的构造函数复制到一个main方法中,拿出你的荧光笔部分并添加了new LinePainter(textPane);
像魅力一样的作品
答案 1 :(得分:2)
以下是从当前行提取文本的代码。 您可以使用相同的逻辑来获取所需的索引并突出显示文本
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;
}
答案 2 :(得分:1)
我认为使用荧光笔可能很难实现 - 我认为这不是它们的设计目标。您可能需要使用自定义绘制代码:
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);
}
}