我有一个关于在JTextPane中着色某些关键字的问题。换句话说,我想制作类似迷你IDE的东西,所以我会编写一些代码,我想为某些关键字提供一种颜色(比如蓝色),例如" public" "私人" ......等问题是它非常慢!!因为每次我都会进入"空间"或"退格" key函数扫描整个文本以给关键字一个颜色,所以当我在textpane中编写大量代码时,它变得非常慢。 这是我匹配关键字的功能:
public void matchWord() throws BadLocationException {
String tokens[] = ArabicParser.tokenNames;
int index = 0;
String textStr[] = textPane.getText().split("\\r?\\n");
for(int i=0 ; i<textStr.length ; i++) {
String t = textStr[i];
StringTokenizer ts2 = new StringTokenizer(t, " ");
while(ts2.hasMoreTokens()) {
String token = ts2.nextToken();
// The iterations are reduced by removing 16 symbols from the search space
for(int j = 3 ; j<tokens.length-5 ; j++) {
if(!(token.equals("؛")) && (tokens[j].equals("'"+token+"'"))) {
changeColor(textPane,token,Color.BLUE,index,token.length());
break;
} else {
changeColor(textPane,token,Color.BLACK,index,token.length());
}
}
index += token.length() + 1;
}
//index -= 1;
}
}
这是我为匹配的单词着色的功能:
private void changeColor(JTextPane tp, String msg, Color c, int beginIndex, int length) throws BadLocationException {
SimpleAttributeSet sas = new SimpleAttributeSet();
StyleConstants.setForeground(sas, c);
StyledDocument doc = (StyledDocument)tp.getDocument();
doc.setCharacterAttributes(beginIndex, length, sas, false);
sas = new SimpleAttributeSet();
StyleConstants.setForeground(sas, Color.BLACK);
tp.setCharacterAttributes(sas, false);
}
并提前感谢=)
答案 0 :(得分:1)
考虑替换StringTokenizer
,因为现代使用已被删除https://stackoverflow.com/a/6983908/1493294
考虑将String tokens[]
重构为HashSet<String> tokens
。散列查找比循环更快,特别是当tokens[]
变大时。
如果您想使用两种以上的颜色,请尝试HashMap<String, Color> tokens
。
另外,在这里遇到两个非常不同的叫做token
和tokens
的东西令人困惑。考虑将tokens[]
重命名为coloredNames[]
,使其明显不同于token
令牌中的textPane
。
考虑使用分析器来查看大部分时间花在哪里。您可能会发现changeColor()
中的重复性工作值得缓存。
如果是这样,请写一个名为ColorChanger
的类。 ColorChanger
将有一个构造函数和一个方法changeColor()
。构造函数将采用(并因此缓存)在循环时不会更改的参数。 ColorChanger.changeColor()
将采用在循环时更改的参数。
答案 1 :(得分:1)
您可以使用DocumentListener仅分析插入TextPane中的文本。这样,您就不需要多次分析整个文本,只检查添加的内容。
为此,您需要获取javax.swing.text.Utilities类的getWordStart
和getWordEnd
方法。这样,您就可以获得插入位置的周围环境。
修改:删除可以更改关键字的状态。删除后,您需要在删除开始位置和getWordStart
之间以及删除结束位置和getWordEnd
之间的文本之间获取文本。例如,如果你删除&#34; continental sur&#34;来自&#34;洲际表面&#34;,你会得到&#34;界面&#34;这可能是一个关键字。
例如,您可以使用此类:
import javax.swing.text.Utilities;
public class Highlighter implements DocumentListener {
public void insertUpdate(final DocumentEvent e) {
highlight(e.getDocument(),e.getOffset(),e.getLength());
}
public void removeUpdate(DocumentEvent e) {
highlight(e.getDocument(), e.getOffset(), 0);
}
public void changedUpdate(DocumentEvent e) {}
private void highlight(final Document doc, final int offset, final int length) {
//Edit the color only when the EDT is ready
SwingUtilities.invokeLater(new Runnable()
public void run() {
//The impacted text is the edition + the surrounding part words.
int start = Utilities.getWordStart(myJTextPane,offset);
int end = Utilities.getWordEnd(myJTextPane,offset+length);
String impactedText = doc.getText(start,end-start);
applyHighlighting(doc, impactedText, offset);
}
});
}
private void applyHighlighting(Document doc, String text, int offset) {
//we review each word and color them if needed.
StringTokenizer tokenizer = new StringTokenizer(text, " \t\n\r\f,.:;?![]'()");
int start = 0;
while(tokenizer.hasMoreTokens()) {
String word = tokenizer.nextToken();
start = text.indexOf(word,start+1);
if(isKeyword(word)) {
//you can use the method you proposed for instance as a start.
changeColor(myJTextPane, word, Color.BLUE, start, word.length());
} else if(offset==0 || !tokenizer.hasMoreTokens()) {
//The first and last word's state can have changed.
//We need to put them back in BLACK if needed.
changeColor(myJTextPane, word, Color.BLACK, start, word.length());
}
}
}
}
答案 2 :(得分:1)
问题是它非常慢!!因为每次我都会进入&#34;空间&#34;或&#34;退格&#34;键功能扫描全文
通过仅处理更改的行,您可以提高效率。
当文档发生变化时,// Start output buffering; it redirects any generated content to a memory buffer
ob_start();
// Include the desired file; this executes the PHP code it contains
// but because of the output buffering, the HTML code is not displayed
// here but buffered
include 'myfile.phtml';
// Get the content of the buffer, clear the buffer, end the buffering
$text = ob_get_clean();
//
// ... more code and/or HTML follows
//
// When you need the content of 'myfile.phtml' you just:
echo($text);
//
// ... more code and/or HTML follows
//
// If you need to display the content of 'myfile.phtml' again you just:
echo($mytext);
可用于通知您。然后,您只能解析受更改影响的行。请记住,可以将多行文本粘贴到文本窗格中,因此您需要处理这种情况。
以下是DocumentListener的简单结构的一些(未经测试的)代码,您可以使用它来处理更改的行:
DocumentListener
需要public class KeywordDocumentListener implements DocumentListener
{
public void insertUpdate(final DocumentEvent e)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
processChangedLines(e.getDocument(), e.getOffset(), e.getLength());
}
});
}
public void removeUpdate(DocumentEvent e)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
processChangedLines(e.getDocument(), e.getOffset(), 0);
}
});
}
public void changedUpdate(DocumentEvent e) {}
private void processChangedLines(Document doc, int offset, int length)
{
// The lines affected by the latest document update
Element rootElement = doc.getDefaultRootElement();
int startLine = rootElement.getElementIndex(offset);
int endLine = rootElement.getElementIndex(offset + length);
// Do the highlighting one line at a time
for (int i = startLine; i <= endLine; i++)
{
int lineStart = rootElement.getElement( i ).getStartOffset();
int lineEnd = rootElement.getElement( i ).getEndOffset() - 1;
String lineText = doc.getText(lineStart, lineEnd - lineStart);
applyHighlighting(doc, lineText, lineStart);
}
}
private void applyHighlighting(Document doc, String text, int lineStart)
{
// Now you can search a line of text for your keywords
// As you find a keyword to highlight you add the lineStart to the search
// location so the highlight is the proper offset in the Document
}
}
,因为您无法在DocumentListener中更新Document,因此这会将代码放在EDT的末尾,以便在侦听器执行完毕后执行。
对于简单的解析,我没有看到使用StringTokeninzer的问题。它比使用正则表达式更有效。
为关键字指定颜色
实际上,除了着色关键字之外,您还要着色每个普通单词,这些单词效率不高。我建议您将整行文本设置为BLACK前景色。然后作为您的解析,您只会突出显示您使用蓝色颜色找到的标记。这将显着减少对Document执行的属性更改次数。
不要为每个令牌创建新的AttributeSet。创建一次AttributeSet,然后为每个令牌重复使用它。