写自己的文本编辑器(一):
高亮关键字
一.
高亮的内容:
需要高亮的内容有:
1.
关键字, 如 public, int, true
等.
2.
运算符, 如 +, -, *, /等
3.
数字
4.
高亮字符串, 如 "example of string"
5.
高亮单行注释
6.
高亮多行注释
二.
实现高亮的核心方法:
StyledDocument.setCharacterAttributes(intoffset, intlength,
AttributeSets, booleanreplace)
三.
文本编辑器选择.
Java中提供的多行文本编辑器有: JTextComponent, JTextArea, JTextPane, JEditorPane等,
都可以使用.
但是因为语法着色中文本要使用多种风格的样式, 所以这些文本编辑器的document要使用StyledDocument.
JTextArea使用的是PlainDocument,
此document不能进行多种格式的着色.
JTextPane, JEditorPane使用的是StyledDocument,
默认就可以使用.
为了实现语法着色,
可以继承自DefaultStyledDocument,
设置其为这些文本编辑器的documet, 或者也可以直接使用JTextPane, JEditorPane来做.
为了方便,
这里就直接使用JTextPane了.
四.
何时进行着色.
当文本编辑器中有字符被插入或者删除时,
文本的内容就发生了变化, 这时检查,
进行着色.
为了监视到文本的内容发生了变化,
要给document添加一个DocumentListener监听器,
在他的removeUpdate和insertUpdate中进行着色处理.
而changedUpdate方法在文本的属性例如前景色,
背景色, 字体等风格改变时才会被调用.
@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:
指变化的字符数.
例如有关键字public, int
单词"publicint",
在"public"和"int"中插入一个空格后变成"public int",
一个单词变成了两个,
这时对"public" 和 "int"进行着色.
着色范围是public中p的位置和int中t的位置加1,
即是pos前面单词开始的下标和pos+len开始单词结束的下标.
所以上例中要着色的范围是"public int".
提供了方法indexOfWordStart来取得pos前单词开始的下标,
方法indexOfWordEnd来取得pos后单词结束的下标.
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;
}
一个字符是单词的有效字符:
是字母, 数字,
下划线.
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);
六.
关键字着色.
从着色范围的开始下标起进行判断,
如果是以字母开或者下划线开头, 则说明是单词,
那么先取得这个单词, 如果这个单词是关键字,
就进行关键字着色, 如果不是,
就进行普通的着色. 着色完这个单词后,
继续后面的着色处理. 已经着色过的字符,
就不再进行着色了.
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)) {
//
如果是关键字, 就进行关键字的着色,
否则使用普通的着色.
//
这里有一点要注意,
在insertUpdate和removeUpdate的方法调用的过程中,
不能修改doc的属性.
//
但我们又要达到能够修改doc的属性,
所以把此任务放到这个方法的外面去执行.
//
实现这一目的, 可以使用新线程,
但放到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的属性,
所以着色的任务放到这两个方法外面,
所以使用了SwingUtilities.invokeLater来实现.
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) {}
}
}
七:
源码
关键字着色的完成代码如下,
可以直接编译运行. 对于数字,
运算符, 字符串等的着色处理在以后的教程中会继续进行详解.
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);
}
}
/**
*
当文本输入区的有字符插入或者删除时, 进行高亮.
*
*
要进行语法高亮, 文本输入组件的document要是styled document才行.
所以不要用JTextArea.
可以使用JTextPane.
*
*
@author Biao
*
*/
class SyntaxHighlighter
implements DocumentListener {
private Set<String>
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);
//
准备关键字
keywords =
new HashSet<String>();
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;
}
}
}
/**
*
对单词进行着色, 并返回单词结束的下标.
*
*
@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)) {
//
如果是关键字, 就进行关键字的着色,
否则使用普通的着色.
//
这里有一点要注意,
在insertUpdate和removeUpdate的方法调用的过程中,
不能修改doc的属性.
//
但我们又要达到能够修改doc的属性,
所以把此任务放到这个方法的外面去执行.
//
实现这一目的, 可以使用新线程,
但放到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(),
返回的是一个文档的结束符,
不会抛出异常. 如果pos<0,
则会抛出异常.
*
所以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, ±表示开始或结束的下标)
*
*
@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时,
它所在的单词结束的下标. ±wor^d± (^表示pos, ±表示开始或结束的下标)
*
*
@param doc
*
@param pos
*
@return
*
@throws BadLocationException
*/
public
int indexOfWordEnd(Document doc,
int pos) throws BadLocationException {
//
从pos开始向前找到第一个非单词字符.
for (; isWordCharacter(doc, pos); ++pos);
return pos;
}
/**
*
如果一个字符是字母, 数字,
下划线, 则返回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();
}
}
/**
*
完成着色任务
*
*
@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) {}
}
}
}
分享到:
相关推荐
在编程中,特别是在开发文本编辑器或者代码编辑器时,我们常常需要实现“关键字着色”功能,也就是根据预定义的关键字将文本中的特定词汇高亮显示,以便于用户更好地理解和阅读代码。这在编程语言学习、代码编写和...
本篇文章将深入探讨如何在C# .NET环境下实现关键字着色功能。 首先,我们需要了解C#语言的关键字。C#是一门面向对象的编程语言,它包含一系列内置关键字,如`class`、`public`、`private`、`void`、`if`、`else`等...
自己写的一个简单的js关键字着色程序。只有100来 行,很简单只要熟悉正则都能看懂。放在这一来为了 备份,二来为了和大家交流。后期会写一个js格式化 的程序,将来会将这段代码整合的里面
1. **关键字着色**:关键字是编程语言中具有特殊含义的标识符,如“Dim”、“For”、“If”等。控件能够自动识别这些关键字并赋予特定颜色,帮助程序员快速区分和理解代码结构。 2. **行号显示**:在代码编辑器中...
珍贵的 关键字着色 代码缩进 完美版,还有很多高级类封装,是我存了3年的好东西。一直用到今天。1年前还有一个类也是很珍贵的。 我一般不乱发资源。要发就是最好的东西来分享,所有的类都是独立的。拖进你的项目绝...
在给定的标题“JTextPane 关键字变色”和描述“SWT JTextPane 可以把控件中需要的字符串的颜色修改成自己想要的颜色”中,我们关注的主要知识点是`JTextPane`如何实现特定关键字的高亮显示,也就是改变颜色。...
除了具有关键字着色的编辑环境外,可以通过外部集成的方式在界面中编译、连接、调试可执行文件,更重要的是对于8086/8088指令系统可以进行源码调试,可以实时的对寄存器、标志位、内存数据进行监视修改,还具备设置...
除了具有关键字着色的编辑环境外,可以通过外部集成的方式在界面中编译、连接、调试可执行文件,更重要的是对于8086/8088指令系统可以进行源码调试,可以实时的对寄存器、标志位、内存数据进行监视修改,还具备设置...
Java Studio 是一个组件可扩充的 Java 开发环境,它是我和我哥哥模仿visual studio界面用Notepad全手工打造的Java期末考核项目,就冒昧叫她Java Studio吧,大家见笑。... Java关键字着色 Java Runtime Process
自定义关键字着色显示高亮的效果 自定义关键字在arm.pro文件中已增加了一些常用关键词的高亮,如果没有你想要的关键词可以按以下格式添加,很简单的。 配色方案的配置方法 首先安装 Cascadia Code 字体文件(可...
其次,Emedit具有编程语言关键字着色功能。这意味着不同类型的代码元素(如变量、函数、关键字)会以不同的颜色显示,这极大地提高了代码的可读性。色彩编码使得在大量代码中快速定位特定元素成为可能,减少了出错的...
采用MFC多文档和递归子程序法实现,支持关键字着色,IDE集成开发环境,使用方便,得到了大家的一致好评,本人更是得到了最高分99分。实现了基本C语言的顺序、分支和循环语句,变量要提前声明。支持int型和char型,...
jcolorize 从FILE或stdin读取,为某些关键字着色并写入stdout。 专门设计用于着色Apache Tomcat和Wildfly AS的日志文件。 Usage: jcolorize [FILE]Examples:jcolorize server.log | less [-R]cat server.log | ...
关键字着色是RustAdmin的一个特色功能,它能帮助管理员快速识别和理解配置文件中的关键内容。在配置文件中,特定的关键字会被高亮显示,使得查找和修改配置变得直观且高效,尤其对于初学者来说,这是一个非常友好的...
editplus的ice语法文件,支持关键字着色等。基于c++的语法文件自己整理的。
"提供多种语言的关键字着色"是指EditPlus支持对不同编程语言的关键字进行颜色区分,使得代码更加易于阅读和理解。这种颜色编码通常包括变量、关键字、函数、注释等不同元素,每种元素都有特定的颜色标识,如蓝色代表...
用于打开大文本文件、大型记事本文件、分页打开、关键字着色和Vs相似,而且支持类似region折叠,非常好用!
很好用的,,适合计算机爱好者,关键字着色,最适合编辑程序语言,java,c/c++.html,等等