package com.biao.mlm.ui;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
// 當(dāng)一個highlight被加到text component中后,每次更新高亮?xí)r,都會去遍歷highlighter的所有highlight,
// 調(diào)用他們對應(yīng)的painter.paing()方法,來進(jìn)行繪制. 所以我們這里只需要加一次highlight, 就可以一直使用.
// 而不是每次更新要高亮的行時就加一個新的highlight, 因為他會動態(tài)地計算當(dāng)前行來進(jìn)行高亮.
public class CurrentLineHighlighter extends MouseAdapter implements Highlighter.HighlightPainter,
CaretListener {
private JTextComponent editor;
private Color color = Color.cyan;
private int previousLine;
public CurrentLineHighlighter() {
}
public CurrentLineHighlighter(JTextComponent editor) {
this(editor, null);
}
public CurrentLineHighlighter(JTextComponent editor, Color color) {
installEditor(editor);
setColor(color);
}
public void installEditor(JTextComponent editor) {
this.editor = editor;
editor.addCaretListener(this);
editor.addMouseListener(this);
editor.addMouseMotionListener(this);
// Turn highlight on
enableHighlight();
}
public void deinstallEditor() {
editor.removeCaretListener(this);
editor.removeMouseListener(this);
editor.removeMouseMotionListener(this);
editor = null;
}
public void enableHighlight() {
// Turn highlight on
try {
editor.getHighlighter().addHighlight(0, 0, this);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
if (color == null) { return; }
this.color = color;
}
@Override
public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent com) {
try {
if (com.getSelectionStart() == com.getSelectionEnd()) { // No
// selection
Rectangle rect = com.modelToView(com.getCaretPosition());
g.setColor(color);
g.fillRect(0, rect.y, com.getWidth(), rect.height);
g.setColor(color.brighter().darker());
// g.drawLine(0, rect.y, com.getWidth(), rect.y);
// g.setColor(color.darker());
g.drawLine(0, rect.y + rect.height - 1, com.getWidth(), rect.y + rect.height - 1);
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/**
* 只清除前一次的高亮,而不是整個editor
*/
public void resetHighlight() {
// 如果把下面的重繪放在一個SwingUtilities.invokeLater里的話,99%的繪制都是好的,
// 但唯一一點就是前一行光標(biāo)所在處一瞬間會有一個很不明顯的空白,如果不仔細(xì)觀察是看不到的
Element root = editor.getDocument().getDefaultRootElement();
int caretPos = editor.getCaretPosition();
try {
// Remove the highlighting from the previously highlighted
// line
Element lineElement = root.getElement(previousLine);
// Might be null if an Undo action was performed on the
// text component
if (lineElement != null) {
// 清除前一次光標(biāo)所在行的高亮0
int start = lineElement.getStartOffset();
Rectangle rect = editor.modelToView(start);
if (rect != null) {
editor.repaint(0, rect.y, editor.getWidth(), rect.height);
// 如果沒有這個, 當(dāng)用中文輸入法輸入后, 鼠標(biāo)再點擊時高亮當(dāng)前行會有可能出問題
rect = editor.modelToView(caretPos);
editor.repaint(0, rect.y, editor.getWidth(), rect.height);
}
}
} catch (BadLocationException ble) {
}
/*
* // We need to use invokeLater to make sure that all updates to the //
* Document have been completed SwingUtilities.invokeLater(new
* Runnable() { public void run() { try { Element root =
* editor.getDocument().getDefaultRootElement(); int caretPos =
* editor.getCaretPosition(); int currentLine =
* root.getElementIndex(caretPos);
*
* // Remove the highlighting from the previously highlighted // line if
* (currentLine != previousLine) { Element lineElement =
* root.getElement(previousLine);
*
* // Might be null if an Undo action was performed on the // text
* component if (lineElement != null) { // 清除前一次光標(biāo)所在行的高亮0 int start =
* lineElement.getStartOffset(); Rectangle rect =
* editor.modelToView(start); if (rect != null) { editor.repaint(0,
* rect.y, editor.getWidth(), rect.height);
*
* // 如果沒有這個, 當(dāng)用中文輸入法輸入后, 鼠標(biāo)再點擊時高亮當(dāng)前行會有可能出問題 rect =
* editor.modelToView(caretPos); editor.repaint(0, rect.y,
* editor.getWidth(), rect.height); } } previousLine = currentLine; } }
* catch (BadLocationException ble) { } } });
*/
}
@Override
public void mousePressed(MouseEvent e) {
resetHighlight();
// editor.repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
resetHighlight();
// editor.repaint();
}
public void caretUpdate(CaretEvent e) {
resetHighlight();
// editor.repaint();
}
}