1 import java.awt.Color; 2 import java.util.Set; 3 4 import javax.swing.JTextPane; 5 import javax.swing.SwingUtilities; 6 import javax.swing.event.DocumentEvent; 7 import javax.swing.event.DocumentListener; 8 import javax.swing.text.AttributeSet; 9 import javax.swing.text.BadLocationException; 10 import javax.swing.text.Document; 11 import javax.swing.text.MutableAttributeSet; 12 import javax.swing.text.SimpleAttributeSet; 13 import javax.swing.text.Style; 14 import javax.swing.text.StyleConstants; 15 import javax.swing.text.StyledDocument; 16 17 /** 18 * 自定义的JTextPane,扩展了JTextPane没有的一些功能(java关键字、单行注释、多行注释加亮) 19 * 20 * @author myafluy@gmail.com 21 * @since 2013-08-17 22 * 23 */ 24 25 public class MyJTextPane extends JTextPane implements DocumentListener { 26 private Set<String> keywords; 27 private Style keywordStyle; 28 private Style normalStyle; 29 private Style classNameStyle; 30 31 public MyJTextPane() { 32 super(); 33 this.getDocument().addDocumentListener(this); 34 // 准备着色使用的样式 35 keywordStyle = ((StyledDocument) getDocument()).addStyle( 36 "Keyword_Style", null); 37 normalStyle = ((StyledDocument) getDocument()).addStyle( 38 "Keyword_Style", null); 39 40 StyleConstants.setForeground(keywordStyle, Color.RED); 41 42 StyleConstants.setForeground(normalStyle, Color.BLACK); 43 44 //获取关键字 45 keywords = KeyWordSet.getKeyWordSet(); 46 System.out.println(keywords.size()); 47 48 } 49 50 /** 51 * 设置全文本属性 52 * 53 * @param attr 54 * @param replace 55 */ 56 public void setTextAttributes(AttributeSet attr, boolean replace) { 57 int p0 = 0; 58 int p1 = this.getText().length(); 59 if (p0 != p1) { 60 StyledDocument doc = getStyledDocument(); 61 doc.setCharacterAttributes(p0, p1 - p0, attr, replace); 62 } else { 63 MutableAttributeSet inputAttributes = getInputAttributes(); 64 if (replace) { 65 inputAttributes.removeAttributes(inputAttributes); 66 } 67 inputAttributes.addAttributes(attr); 68 } 69 } 70 71 /** 72 * 单行注释 73 */ 74 public void setSingleLineNoteCharacterAttributes() { 75 String text = this.getText(); 76 int startPointer = 0; 77 int endPointer = 0; 78 if ((startPointer = text.indexOf("//")) == -1) { 79 return; 80 } 81 82 while ((endPointer = text.substring(startPointer).indexOf(" ")) != -1) { 83 endPointer = startPointer + endPointer; 84 if (startPointer >= endPointer) { 85 break; 86 } 87 int hangshu = text.substring(0, endPointer).split("\n").length; 88 System.out.println("hangshu:" + hangshu); 89 SwingUtilities 90 .invokeLater(new ColouringWord(this, startPointer - hangshu 91 + 1, endPointer - hangshu, new Color(63, 217, 95))); 92 startPointer = text.substring(endPointer + 1).indexOf("//"); 93 startPointer = startPointer + endPointer + 1; 94 95 } 96 } 97 98 /** 99 * 多行注释 100 */ 101 public void setMultiLineNoteCharacterAttributes() { 102 String text = this.getText(); 103 int startPointer = 0; 104 int endPointer = 0; 105 if ((startPointer = text.indexOf("/*")) == -1) { 106 return; 107 } 108 109 while ((endPointer = text.substring(startPointer).indexOf("*/")) != -1) { 110 endPointer = startPointer + endPointer; 111 if (startPointer >= endPointer) { 112 break; 113 } 114 int hangshu = text.substring(0, endPointer).split("\n").length; 115 int kuaju = text.substring(startPointer, endPointer).split("\n").length; 116 SwingUtilities.invokeLater(new ColouringWord(this, startPointer 117 - hangshu + kuaju, endPointer + 3 - hangshu, new Color(63, 118 217, 95))); 119 startPointer = text.substring(endPointer + 1).indexOf("/*"); 120 startPointer = startPointer + endPointer + 1; 121 122 } 123 } 124 125 /** 126 * 实时加亮关键字 127 * @param styledDocument 128 * @param pos 129 * @param len 130 * @throws BadLocationException 131 */ 132 public void myColouring(StyledDocument styledDocument, int pos, int len) 133 throws BadLocationException { 134 int start = indexOfWordStart(styledDocument, pos); 135 int end = indexOfWordEnd(styledDocument, pos + len); 136 137 char ch; 138 while (start < end) { 139 ch = getCharAt(styledDocument, start); 140 if (Character.isLetter(ch) || ch == '_') {//判断是否为字母 141 start = myColouringWord(styledDocument, start); 142 } else { 143 SwingUtilities.invokeLater(new ColouringTask(styledDocument, 144 start, 1, normalStyle)); 145 ++start; 146 } 147 } 148 } 149 150 /** 151 * 实时着色 152 * 153 * @param doc 154 * @param pos 155 * @return 156 * @throws BadLocationException 157 */ 158 public int myColouringWord(StyledDocument doc, int pos) 159 throws BadLocationException { 160 int wordEnd = indexOfWordEnd(doc, pos); 161 String word = doc.getText(pos, wordEnd - pos); 162 163 if (keywords.contains(word)) { 164 SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd 165 - pos, keywordStyle)); 166 } else { 167 SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd 168 - pos, normalStyle)); 169 } 170 171 return wordEnd; 172 } 173 174 /** 175 * 取得在文档中下标在pos处的字符. 176 * 177 * @param doc 178 * @param pos 179 * @return 180 * @throws BadLocationException 181 */ 182 public char getCharAt(Document doc, int pos) throws BadLocationException { 183 return doc.getText(pos, 1).charAt(0); 184 } 185 186 /** 187 * 取得下标为pos时, 它所在的单词开始的下标. 188 * 189 * @param doc 190 * @param pos 191 * @return 192 * @throws BadLocationException 193 */ 194 public int indexOfWordStart(Document doc, int pos) 195 throws BadLocationException { 196 // 从pos开始向前找到第一个非单词字符. 197 for (; pos > 0 && isWordCharacter(doc, pos - 1); --pos) 198 ; 199 200 return pos; 201 } 202 203 /** 204 * 取得下标为pos时, 它所在的单词结束的下标. 205 * 206 * @param doc 207 * @param pos 208 * @return 209 * @throws BadLocationException 210 */ 211 public int indexOfWordEnd(Document doc, int pos) 212 throws BadLocationException { 213 // 从pos开始向前找到第一个非单词字符. 214 for (; isWordCharacter(doc, pos); ++pos) 215 ; 216 217 return pos; 218 } 219 220 /** 221 * 如果一个字符是字母, 数字, 下划线, 则返回true. 222 * 223 * @param doc 224 * @param pos 225 * @return 226 * @throws BadLocationException 227 */ 228 public boolean isWordCharacter(Document doc, int pos) 229 throws BadLocationException { 230 char ch = getCharAt(doc, pos); 231 if (Character.isLetter(ch) || Character.isDigit(ch) || ch == '_') { 232 return true; 233 } 234 return false; 235 } 236 237 @Override 238 // 给出属性或属性集发生了更改的通知 239 public void changedUpdate(DocumentEvent e) { 240 241 } 242 243 @Override 244 // 给出对文档执行了插入操作的通知 245 public void insertUpdate(DocumentEvent e) { 246 try { 247 myColouring((StyledDocument) e.getDocument(), e.getOffset(), 248 e.getLength()); 249 // noteFinder.ColorNote(this.getText());// 给注释上色 250 setSingleLineNoteCharacterAttributes(); 251 setMultiLineNoteCharacterAttributes(); 252 } catch (BadLocationException e1) { 253 e1.printStackTrace(); 254 } 255 } 256 257 @Override 258 // 给出移除了一部分文档的通知 259 public void removeUpdate(DocumentEvent e) { 260 try { 261 // 因为删除后光标紧接着影响的单词两边, 所以长度就不需要了 262 myColouring((StyledDocument) e.getDocument(), e.getOffset(), 0); 263 // noteFinder.ColorNote(this.getText());// 给注释上色 264 setSingleLineNoteCharacterAttributes(); 265 setMultiLineNoteCharacterAttributes(); 266 } catch (BadLocationException e1) { 267 e1.printStackTrace(); 268 } 269 } 270 271 /** 272 * 多线程绘制颜色 273 * 274 * 275 * 276 */ 277 private class ColouringTask implements Runnable { 278 private StyledDocument doc; 279 private Style style; 280 private int pos; 281 private int len; 282 283 public ColouringTask(StyledDocument doc, int pos, int len, Style style) { 284 this.doc = doc; 285 this.pos = pos; 286 this.len = len; 287 this.style = style; 288 } 289 290 public void run() { 291 try { 292 // 这里就是对字符进行着色 293 doc.setCharacterAttributes(pos, len, style, false); 294 } catch (Exception e) { 295 } 296 } 297 } 298 299 } 300 301 /** 302 * 多线程绘制颜色 303 * 304 * 305 * 306 */ 307 class ColouringWord implements Runnable { 308 private int startPointer; 309 private int endPointer; 310 private Color color; 311 private JTextPane jTextPane; 312 313 public ColouringWord(JTextPane jTextPane, int pos, int len, Color color) { 314 this.jTextPane = jTextPane; 315 this.startPointer = pos; 316 this.endPointer = len; 317 this.color = color; 318 } 319 320 @Override 321 public void run() { 322 SimpleAttributeSet attributeSet = new SimpleAttributeSet(); 323 StyleConstants.setForeground(attributeSet, color); 324 boolean replace = false; 325 int p0 = startPointer; 326 int p1 = endPointer; 327 if (p0 != p1) { 328 StyledDocument doc = jTextPane.getStyledDocument(); 329 doc.setCharacterAttributes(p0, p1 - p0, attributeSet, replace); 330 } else { 331 MutableAttributeSet inputAttributes = jTextPane 332 .getInputAttributes(); 333 if (replace) { 334 inputAttributes.removeAttributes(inputAttributes); 335 } 336 inputAttributes.addAttributes(attributeSet); 337 } 338 } 339 }