Eclipse 是一個開放源代碼的、基于Java的可擴展開發(fā)平臺。就其本身而言,它只是一個框架和一組服務(wù),用于通過插件組件構(gòu)建開發(fā)環(huán)境。 eclipse可以用來作為 Java 集成開發(fā)環(huán)境(IDE)來使用
專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)富陽免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上1000家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。
一. 高亮的內(nèi)容:
需要高亮的內(nèi)容有:
1. 關(guān)鍵字, 如 public, int, true 等.
2. 運算符, 如 +, -, *, /等
3. 數(shù)字
4. 高亮字符串, 如 "example of string"
5. 高亮單行注釋
6. 高亮多行注釋
二. 實現(xiàn)高亮的核心方法:
StyledDocument.setCharacterAttributes(int offset, int length, AttributeSet s, boolean replace)
三. 文本編輯器選擇.
Java中提供的多行文本編輯器有: JTextComponent, JTextArea, JTextPane, JEditorPane等, 都可以使用. 但是因為語法著色中文本要使用多種風(fēng)格的樣式, 所以這些文本編輯器的document要使用StyledDocument.
JTextArea使用的是PlainDocument, 此document不能進行多種格式的著色.
JTextPane, JEditorPane使用的是StyledDocument, 默認就可以使用.
為了實現(xiàn)語法著色, 可以繼承自DefaultStyledDocument, 設(shè)置其為這些文本編輯器的documet, 或者也可以直接使用JTextPane, JEditorPane來做. 為了方便, 這里就直接使用JTextPane了.
四. 何時進行著色.
當(dāng)文本編輯器中有字符被插入或者刪除時, 文本的內(nèi)容就發(fā)生了變化, 這時檢查, 進行著色.
為了監(jiān)視到文本的內(nèi)容發(fā)生了變化, 要給document添加一個DocumentListener監(jiān)聽器, 在他的removeUpdate和insertUpdate中進行著色處理.
而changedUpdate方法在文本的屬性例如前景色, 背景色, 字體等風(fēng)格改變時才會被調(diào)用.
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void insertUpdate(DocumentEvent e) {
try {
colouring((StyledDocument) e.getDocument(), e.getOffset(), e.getLength());
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
@Override
public void removeUpdate(DocumentEvent e) {
try {
// 因為刪除后光標緊接著影響的單詞兩邊, 所以長度就不需要了
colouring((StyledDocument) e.getDocument(), e.getOffset(), 0);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
五. 著色范圍:
pos: 指變化前光標的位置.
len: 指變化的字符數(shù).
例如有關(guān)鍵字public, int
單詞"publicint", 在"public"和"int"中插入一個空格后變成"public int", 一個單詞變成了兩個, 這時對"public" 和 "int"進行著色.
著色范圍是public中p的位置和int中t的位置加1, 即是pos前面單詞開始的下標和pos+len開始單詞結(jié)束的下標. 所以上例中要著色的范圍是"public int".
提供了方法indexOfWordStart來取得pos前單詞開始的下標, 方法indexOfWordEnd來取得pos后單詞結(jié)束的下標.
public int indexOfWordStart(Document doc, int pos) throws BadLocationException {
// 從pos開始向前找到第一個非單詞字符.
for (; pos 0 isWordCharacter(doc, pos - 1); --pos);
return pos;
}
public int indexOfWordEnd(Document doc, int pos) throws BadLocationException {
// 從pos開始向前找到第一個非單詞字符.
for (; isWordCharacter(doc, pos); ++pos);
return pos;
}
一個字符是單詞的有效字符: 是字母, 數(shù)字, 下劃線.
public boolean isWordCharacter(Document doc, int pos) throws BadLocationException {
char ch = getCharAt(doc, pos); // 取得在文檔中pos位置處的字符
if (Character.isLetter(ch) || Character.isDigit(ch) || ch == '_') { return true; }
return false;
}
所以著色的范圍是[start, end] :
int start = indexOfWordStart(doc, pos);
int end = indexOfWordEnd(doc, pos + len);
六. 關(guān)鍵字著色.
從著色范圍的開始下標起進行判斷, 如果是以字母開或者下劃線開頭, 則說明是單詞, 那么先取得這個單詞, 如果這個單詞是關(guān)鍵字, 就進行關(guān)鍵字著色, 如果不是, 就進行普通的著色. 著色完這個單詞后, 繼續(xù)后面的著色處理. 已經(jīng)著色過的字符, 就不再進行著色了.
public void colouring(StyledDocument doc, int pos, int len) throws BadLocationException {
// 取得插入或者刪除后影響到的單詞.
// 例如"public"在b后插入一個空格, 就變成了:"pub lic", 這時就有兩個單詞要處理:"pub"和"lic"
// 這時要取得的范圍是pub中p前面的位置和lic中c后面的位置
int start = indexOfWordStart(doc, pos);
int end = indexOfWordEnd(doc, pos + len);
char ch;
while (start end) {
ch = getCharAt(doc, start);
if (Character.isLetter(ch) || ch == '_') {
// 如果是以字母或者下劃線開頭, 說明是單詞
// pos為處理后的最后一個下標
start = colouringWord(doc, start);
} else {
//SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));
++start;
}
}
}
public int colouringWord(StyledDocument doc, int pos) throws BadLocationException {
int wordEnd = indexOfWordEnd(doc, pos);
String word = doc.getText(pos, wordEnd - pos); // 要進行著色的單詞
if (keywords.contains(word)) {
// 如果是關(guān)鍵字, 就進行關(guān)鍵字的著色, 否則使用普通的著色.
// 這里有一點要注意, 在insertUpdate和removeUpdate的方法調(diào)用的過程中, 不能修改doc的屬性.
// 但我們又要達到能夠修改doc的屬性, 所以把此任務(wù)放到這個方法的外面去執(zhí)行.
// 實現(xiàn)這一目的, 可以使用新線程, 但放到swing的事件隊列里去處理更輕便一點.
SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, keywordStyle));
} else {
SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));
}
return wordEnd;
}
因為在insertUpdate和removeUpdate方法中不能修改document的屬性, 所以著色的任務(wù)放到這兩個方法外面, 所以使用了SwingUtilities.invokeLater來實現(xiàn).
private class ColouringTask implements Runnable {
private StyledDocument doc;
private Style style;
private int pos;
private int len;
public ColouringTask(StyledDocument doc, int pos, int len, Style style) {
this.doc = doc;
this.pos = pos;
this.len = len;
this.style = style;
}
public void run() {
try {
// 這里就是對字符進行著色
doc.setCharacterAttributes(pos, len, style, true);
} catch (Exception e) {}
}
}
七: 源碼
關(guān)鍵字著色的完成代碼如下, 可以直接編譯運行. 對于數(shù)字, 運算符, 字符串等的著色處理在以后的教程中會繼續(xù)進行詳解.
import java.awt.Color;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
public class HighlightKeywordsDemo {
public static void main(String[] args) {
JFrame frame = new JFrame();
JTextPane editor = new JTextPane();
editor.getDocument().addDocumentListener(new SyntaxHighlighter(editor));
frame.getContentPane().add(editor);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
}
/**
* 當(dāng)文本輸入?yún)^(qū)的有字符插入或者刪除時, 進行高亮.
*
* 要進行語法高亮, 文本輸入組件的document要是styled document才行. 所以不要用JTextArea. 可以使用JTextPane.
*
* @author Biao
*
*/
class SyntaxHighlighter implements DocumentListener {
private SetString keywords;
private Style keywordStyle;
private Style normalStyle;
public SyntaxHighlighter(JTextPane editor) {
// 準備著色使用的樣式
keywordStyle = ((StyledDocument) editor.getDocument()).addStyle("Keyword_Style", null);
normalStyle = ((StyledDocument) editor.getDocument()).addStyle("Keyword_Style", null);
StyleConstants.setForeground(keywordStyle, Color.RED);
StyleConstants.setForeground(normalStyle, Color.BLACK);
// 準備關(guān)鍵字
keywords = new HashSetString();
keywords.add("public");
keywords.add("protected");
keywords.add("private");
keywords.add("_int9");
keywords.add("float");
keywords.add("double");
}
public void colouring(StyledDocument doc, int pos, int len) throws BadLocationException {
// 取得插入或者刪除后影響到的單詞.
// 例如"public"在b后插入一個空格, 就變成了:"pub lic", 這時就有兩個單詞要處理:"pub"和"lic"
// 這時要取得的范圍是pub中p前面的位置和lic中c后面的位置
int start = indexOfWordStart(doc, pos);
int end = indexOfWordEnd(doc, pos + len);
char ch;
while (start end) {
ch = getCharAt(doc, start);
if (Character.isLetter(ch) || ch == '_') {
// 如果是以字母或者下劃線開頭, 說明是單詞
// pos為處理后的最后一個下標
start = colouringWord(doc, start);
} else {
SwingUtilities.invokeLater(new ColouringTask(doc, start, 1, normalStyle));
++start;
}
}
}
/**
* 對單詞進行著色, 并返回單詞結(jié)束的下標.
*
* @param doc
* @param pos
* @return
* @throws BadLocationException
*/
public int colouringWord(StyledDocument doc, int pos) throws BadLocationException {
int wordEnd = indexOfWordEnd(doc, pos);
String word = doc.getText(pos, wordEnd - pos);
if (keywords.contains(word)) {
// 如果是關(guān)鍵字, 就進行關(guān)鍵字的著色, 否則使用普通的著色.
// 這里有一點要注意, 在insertUpdate和removeUpdate的方法調(diào)用的過程中, 不能修改doc的屬性.
// 但我們又要達到能夠修改doc的屬性, 所以把此任務(wù)放到這個方法的外面去執(zhí)行.
// 實現(xiàn)這一目的, 可以使用新線程, 但放到swing的事件隊列里去處理更輕便一點.
SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, keywordStyle));
} else {
SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));
}
return wordEnd;
}
/**
* 取得在文檔中下標在pos處的字符.
*
* 如果pos為doc.getLength(), 返回的是一個文檔的結(jié)束符, 不會拋出異常. 如果pos0, 則會拋出異常.
* 所以pos的有效值是[0, doc.getLength()]
*
* @param doc
* @param pos
* @return
* @throws BadLocationException
*/
public char getCharAt(Document doc, int pos) throws BadLocationException {
return doc.getText(pos, 1).charAt(0);
}
/**
* 取得下標為pos時, 它所在的單詞開始的下標. ?±wor^d?± (^表示pos, ?±表示開始或結(jié)束的下標)
*
* @param doc
* @param pos
* @return
* @throws BadLocationException
*/
public int indexOfWordStart(Document doc, int pos) throws BadLocationException {
// 從pos開始向前找到第一個非單詞字符.
for (; pos 0 isWordCharacter(doc, pos - 1); --pos);
return pos;
}
/**
* 取得下標為pos時, 它所在的單詞結(jié)束的下標. ?±wor^d?± (^表示pos, ?±表示開始或結(jié)束的下標)
*
* @param doc
* @param pos
* @return
* @throws BadLocationException
*/
public int indexOfWordEnd(Document doc, int pos) throws BadLocationException {
// 從pos開始向前找到第一個非單詞字符.
for (; isWordCharacter(doc, pos); ++pos);
return pos;
}
/**
* 如果一個字符是字母, 數(shù)字, 下劃線, 則返回true.
*
* @param doc
* @param pos
* @return
* @throws BadLocationException
*/
public boolean isWordCharacter(Document doc, int pos) throws BadLocationException {
char ch = getCharAt(doc, pos);
if (Character.isLetter(ch) || Character.isDigit(ch) || ch == '_') { return true; }
return false;
}
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void insertUpdate(DocumentEvent e) {
try {
colouring((StyledDocument) e.getDocument(), e.getOffset(), e.getLength());
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
@Override
public void removeUpdate(DocumentEvent e) {
try {
// 因為刪除后光標緊接著影響的單詞兩邊, 所以長度就不需要了
colouring((StyledDocument) e.getDocument(), e.getOffset(), 0);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
/**
* 完成著色任務(wù)
*
* @author Biao
*
*/
private class ColouringTask implements Runnable {
private StyledDocument doc;
private Style style;
private int pos;
private int len;
public ColouringTask(StyledDocument doc, int pos, int len, Style style) {
this.doc = doc;
this.pos = pos;
this.len = len;
this.style = style;
}
public void run() {
try {
// 這里就是對字符進行著色
doc.setCharacterAttributes(pos, len, style, true);
} catch (Exception e) {}
}
}
}
1、Eclipse - IBM甩出來給開源社區(qū)的IDE,其本身就是使用Java開發(fā)的。\x0d\x0a2、MyEclipse - 把Eclipse包裝了一下,加了J2EE企業(yè)開發(fā)的許多功能強大的插件。\x0d\x0a3、NetBeans - SUN公司自己開發(fā)的Java開發(fā)環(huán)境,功能挺多的。\x0d\x0a4、還有一些超喜歡手工編寫Java代碼的牛人喜歡使用帶語法著色功能的純文本編輯器編寫Java程序,代碼寫完后在命令提示符下編譯運行。這種方式只適用寫少量代碼或作為學(xué)習(xí)使用,開發(fā)大型項目不適用,因為效率很低。