要实现高亮效果,我们需要把JEditorPane默认的编辑工具类覆盖掉。我们自己实现自己的编辑工具类。
在swing中,已经有一些工具类的子类,我们直接继承该子类就行了,我们继承StyledEditorKit类。
如下:
public class JavaCodeEditor extends StyledEditorKit{
@Override
public Document createDefaultDocument() {
return super.createDefaultDocument();
}
@Override
public ViewFactory getViewFactory() {
return new JavaViewFactory();
}
}
上面这段代码,我们主要关注getViewFactory方法。这个方法返回一个试图工厂类,我们就是在这个工厂类中处理我们的文本内容。
代码如下:
public class JavaViewFactory implements ViewFactory{
@Override
public View create(Element elem) {
return new XmlView(elem);
}
}
这个类有一个创建工厂的方法,是未实现的,我们自己定义一个类实现View接口然后返回。
View接口以及有很多实现子类,我们选择继承PlainView即可。
代码如下:
import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import javax.swing.text.PlainView;
import javax.swing.text.Segment;
import javax.swing.text.Utilities;
public class XmlView extends PlainView {
private static HashMap<Pattern, Color> patternColors;
private static String TAG_PATTERN = "(</?[A-Za-z\\-_0-9]*)\\s?>?";
private static String TAG_ATTRIBUTE_PATTERN = "\\s(\\w*)\\=";
private static String TAG_ATTRIBUTE_VALUE = "[a-z\\-]*\\=(\"[^\"]*\")";
private static String TAG_COMMENT = "(<\\!--[^-]*+(?>-(?!->))*+-->)";
private static String TAG_COMMENT_JAVA = "(/\\*\\*\\s+[\\u4e00-\\u9fa5]+:[\\w\\d\\(\\),]+\\s+\\*/)";
private static String TAG_CDATA = "(<\\!\\[CDATA\\[)";
private static String TAG_CDATA_END = "(\\]\\]>)";
private static String TAG_JAVA = "(public|private|return)";
static {
// NOTE: the order is important!
patternColors = new LinkedHashMap<Pattern, Color>();
patternColors.put(Pattern.compile(TAG_PATTERN), new Color(0, 0, 128));
patternColors.put(Pattern.compile(TAG_CDATA), Color.GRAY);
patternColors.put(Pattern.compile(TAG_CDATA_END), Color.GRAY);
patternColors.put(Pattern.compile(TAG_ATTRIBUTE_PATTERN), new Color(40, 0, 252));
patternColors.put(Pattern.compile(TAG_ATTRIBUTE_VALUE), new Color(43, 128, 0));
patternColors.put(Pattern.compile(TAG_COMMENT), new Color(0, 128, 0));
patternColors.put(Pattern.compile(TAG_COMMENT_JAVA), new Color(0, 128, 0));
patternColors.put(Pattern.compile(TAG_JAVA), new Color(127,0,85));
}
public XmlView(Element element) {
super(element);
getDocument().putProperty(PlainDocument.tabSizeAttribute, 4);
}
@Override
protected int drawUnselectedText(Graphics graphics, int x, int y, int p0,
int p1) throws BadLocationException {
Document doc = getDocument();
String text = doc.getText(p0, p1 - p0);
Segment segment = getLineBuffer();
SortedMap<Integer, Integer> startMap = new TreeMap<Integer, Integer>();
SortedMap<Integer, Color> colorMap = new TreeMap<Integer, Color>();
for (Map.Entry<Pattern, Color> entry : patternColors.entrySet()) {
Matcher matcher = entry.getKey().matcher(text);
while (matcher.find()) {
startMap.put(matcher.start(1), matcher.end());
colorMap.put(matcher.start(1), entry.getValue());
}
}
int i = 0;
for (Map.Entry<Integer, Integer> entry : startMap.entrySet()) {
int start = entry.getKey();
int end = entry.getValue();
if (i < start) {
graphics.setColor(Color.black);
doc.getText(p0 + i, start - i, segment);
x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
}
graphics.setColor(colorMap.get(start));
i = end;
doc.getText(p0 + start, i - start, segment);
x = Utilities.drawTabbedText(segment, x, y, graphics, this, start);
}
if (i < text.length()) {
graphics.setColor(Color.black);
doc.getText(p0 + i, text.length() - i, segment);
x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
}
return x;
}
}
上面代码的大意就是:定义需要高亮代码的正则表达式,然后把表达式和颜色一起放入Map中。PlainView中的drawUnselectedText方法会逐行渲染JEditorPane的内容。
第一个for循环就是循环 表达式的Map,用表达式来找当前行里符合内容的关键字,并把起始位置保存到startMap 中,同时把颜色也存入colorMap 中,key就是符合表达式的字符的index。
第二个for循环是循环startMap,根据起始的坐标,获取colorMap 中的颜色,然后渲染文本。
如果 i 的位置小于 第一个匹配成功的字符串位置,那么从i的位置到第一匹配成功的位置设置颜色为黑色,同理,如果把所有匹配的字符串都已经设置颜色,i的位置任然没有到达本行字符串结尾,那么就把i的位置到text.length之间的内容设置为黑色。
上面三个类创建完成就可以进行测试了。
创建一个JFrame来测试,代码如下:
import javax.swing.JEditorPane;
import javax.swing.JFrame;
public class MyFrame extends JFrame{
private JEditorPane editorPane;
public MyFrame (){
editorPane = new JEditorPane();
editorPane.setBounds(0, 0, 1000, 600);
editorPane.setEditorKit(new JavaCodeEditor());
editorPane.setText( "\n<update id=\"update\" parameterClass=\"map\">\n"+
"\tupdate tableName a \n"+
"\t\t<dynamic prepend=\"SET\">\n"+
"\t \t\t\t<isPropertyAvailable prepend=\",\" property=\"desc\"> <!--\t命令获得:tableName\t-->\n"+
"\t\t\t\ta.desc = #desc# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t\t<isPropertyAvailable prepend=\",\" property=\"aac001\"> <!--\t人员ID:VARCHAR2(20)\t-->\n"+
"\t\t\t\ta.aac001 = #aac001# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t\t<isPropertyAvailable prepend=\",\" property=\"aac003\"> <!--\t姓名:VARCHAR2(60)\t-->\n"+
"\t\t\t\ta.aac003 = #aac003# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t\t<isPropertyAvailable prepend=\",\" property=\"aac004\"> <!--\t性别:VARCHAR2(6)\t-->\n"+
"\t\t\t\ta.aac004 = #aac004# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t\t<isPropertyAvailable prepend=\",\" property=\"aac005\"> <!--\t民族:VARCHAR2(6)\t-->\n"+
"\t\t\t\ta.aac005 = #aac005# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t\t<isPropertyAvailable prepend=\",\" property=\"aac006\"> <!--\t出生日期:DATE\t-->\n"+
"\t\t\t\ta.aac006 = #aac006# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t\t<isPropertyAvailable prepend=\",\" property=\"aaf039\"> <!--\t工资:NUMBER(14,2)\t-->\n"+
"\t\t\t\ta.aaf039 = #aaf039# \n"+
"\t\t\t</isPropertyAvailable>\n"+
"\t\t</dynamic>\n"+
"\twhere a.index = #index#\n"+
"</update>\n"+
"/** 工资:NUMBER(14,2) */\n"+
"private BigDecimal aaf039;\n"+
"<![CDATA[ AND aae001 = #aae001# ]]>");
add(editorPane);
setSize(1000,600);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new MyFrame ();
}
}
代码有一行:editorPane.setEditorKit(new JavaCodeEditor()); 这里把我们自己创建的编辑器替换editorPane默认的编辑器。
运行效果如下:
这里最关键的地方就是正则表达式了,所以正则表达式一定要过关。get到的小伙伴给个点赞吧