【java】【swing】【JTextPane】自定义的JTextPane,扩展了JTextPane没有的一些功能,java关键字、单行注释、多行注释加亮

  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("\n")) != -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 }