DocumentListener 会减慢 Document.setCharacterAttributes 方法的速度吗?
这是我在这个网站上的第一个问题,虽然不是我第一次进入以消除我的疑虑,很棒的网页。 :)
我正在编写一个 java 程序,该程序在 JTextPane 中突出显示代码,并且我正在更改突出显示的完成方式。我使用 JTabbedPane 让用户同时编辑多个文件,并且我曾经使用计时器执行文档突出显示,现在我构建了一个在单独线程中运行的突出显示队列,并实现了一个排队的 DocumentListener发生更改时的文档。
但我有一个非常大的问题,如果我通过 DocumentListener 添加文档,突出显示过程需要很长时间,而如果我通过直接从 JTextPane 获取文档将其添加到主类中,则只需要几毫秒。 我在代码中执行了多个基准测试,发现从 DocumentListener 添加文档时花费如此多时间执行的是 Document.setCharacterAttributes() 方法。
下面是通过 DocumentListener 添加文档的方法:
// eventType: 0 - insertUpdate / 1- removeUpdate
private void queueChange(javax.swing.event.DocumentEvent e, int eventType){
StyledDocument doc = (StyledDocument) e.getDocument();
int changeLength = e.getLength();
int changeOffset = e.getOffset();
int length = doc.getLength();
String title = (String) doc.getProperty("title");
String text;
try {
text = doc.getText(0, length);
if (changeLength != 1) {
Element element = doc.getDefaultRootElement();
int startLn = element.getElement(element.getElementIndex(changeOffset)).getStartOffset();
int endLn = element.getElement(element.getElementIndex(changeOffset + changeLength)).getEndOffset() - 1;
Engine.addDocument(doc, startLn, endLn, title, text);
} else {
if(eventType == 1){
changeOffset = changeOffset - changeLength;
}
int startLn = text.lastIndexOf("\n", changeOffset) + 1;
int endLn = text.indexOf("\n", changeOffset);
if (endLn < 0) {
if (length != startLn) {
endLn = length;
Engine.addDocument(doc, startLn, endLn, title, text);
}
} else if (startLn != endLn && startLn < endLn) {
Engine.addDocument(doc, startLn, endLn, title, text);
}
}
} catch (BadLocationException ex) {
Engine.crashEngine();
}
}
如果我使用此方法添加一个 2k 行的文档,则需要大约 1900 毫秒来突出显示整个文档,而如果我使用插入符侦听方法将文档添加到突出显示队列中,则需要大约 1900 毫秒的时间。大约需要 500 毫秒。
下面是插入符侦听方法的一部分,用于在加载时突出显示整个文档:
if (loadFile == true) {
isKey = false;
doc = edit[currentTab].Editor.getStyledDocument();
try {
Highlight.addDocument(doc, 0, doc.getLength(),
Scripts.getTitleAt(currentTab), doc.getText(0, doc.getLength()));
} catch (BadLocationException ex) {
ex.printStackTrace();
}
loadFile = false;
}
注意:Highlight/Engine.addDocument() 方法有五个参数: (StyledDocument doc,int start, int end, String tabTitle, String文档文本)。开始和结束都表示需要突出显示的区域。
我将不胜感激与此问题相关的任何帮助,因为我已经尝试解决它几天了,但在互联网上找不到类似的内容。 :(
顺便说一句,有谁知道 Document.setCharacterAttributes 和 Document.setParagraphAttributes 之间的实际区别吗?:P
this is my first question in this site, though is not the first time I enter to clear my doubts, awesome webpage. :)
I'm writing a java program that highlights code in a JTextPane and I'm changing the way highlights are done. I'm using a JTabbedPane to let the user edit more than one file at the same time and I used to perform document highlights using a Timer, now I've built a highlight queue that runs in a separate thread and implemented a DocumentListener that queues the documents as changes take place.
But I have a really big problem, if I add the document via DocumentListener, the Highlight process takes a really long time while if I add it in the main class by getting the document directly from the JTextPane, it takes just a few milliseconds.
I've performed multiple benchmarks in my code and found out that what takes so much time to be performed when the document is added from the DocumentListener is the method Document.setCharacterAttributes().
Here is the method that adds documents via DocumentListener:
// eventType: 0 - insertUpdate / 1- removeUpdate
private void queueChange(javax.swing.event.DocumentEvent e, int eventType){
StyledDocument doc = (StyledDocument) e.getDocument();
int changeLength = e.getLength();
int changeOffset = e.getOffset();
int length = doc.getLength();
String title = (String) doc.getProperty("title");
String text;
try {
text = doc.getText(0, length);
if (changeLength != 1) {
Element element = doc.getDefaultRootElement();
int startLn = element.getElement(element.getElementIndex(changeOffset)).getStartOffset();
int endLn = element.getElement(element.getElementIndex(changeOffset + changeLength)).getEndOffset() - 1;
Engine.addDocument(doc, startLn, endLn, title, text);
} else {
if(eventType == 1){
changeOffset = changeOffset - changeLength;
}
int startLn = text.lastIndexOf("\n", changeOffset) + 1;
int endLn = text.indexOf("\n", changeOffset);
if (endLn < 0) {
if (length != startLn) {
endLn = length;
Engine.addDocument(doc, startLn, endLn, title, text);
}
} else if (startLn != endLn && startLn < endLn) {
Engine.addDocument(doc, startLn, endLn, title, text);
}
}
} catch (BadLocationException ex) {
Engine.crashEngine();
}
}
If I add a document with 2k lines with this method, it takes ~1900 ms to highlight the whole document, while if I add the document to the highlight queue by using a caret listening method it takes ~500 ms.
Here's a part of the caret listening method that is used to highlight whole documents when they're loaded:
if (loadFile == true) {
isKey = false;
doc = edit[currentTab].Editor.getStyledDocument();
try {
Highlight.addDocument(doc, 0, doc.getLength(),
Scripts.getTitleAt(currentTab), doc.getText(0, doc.getLength()));
} catch (BadLocationException ex) {
ex.printStackTrace();
}
loadFile = false;
}
Note: the Highlight/Engine.addDocument() method has five parameters: (StyledDocument doc,int start, int end, String tabTitle, String docText). Start and end both indicate the region where highlighting is needed.
I will appreciate any help related to this problem cause I've been trying to solve it for a few days and I can't find anything similar on the Internet. :(
Btw, does anyone know the actual difference between Document.setCharacterAttributes and Document.setParagraphAttributes? :P
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
也许您的代码中有某种递归导致了问题。使用 DocumentEvent,您只需担心添加和删除。您无需担心更改,因为这些是属性更改。
也许您添加了一些安排突出显示的文本,但是当您更改文本的属性时,您安排了另一个突出显示任务。
Maybe you have some kind of recursion in your code that is causing the problem. With the DocumentEvent you should only worry about additions and removals. You don't need to worry about changes since those are attribute changes.
Maybe you add some text which schedules the highlighting, but then when you change the attributes of the text you schedule another highllighting task.
您可以尝试设置一个标志来指示是用户更改还是您的 API 更改。在 Engine.addDocument() 的开头将标志设置为 API 状态,并在更改完成后将其重置回来。
在您的侦听器中检查标志并跳过 API 的更改。
您写道“我通过设置文档一部分的字符属性来突出显示文本,因此该方法不会插入更多文本”。我不确定它不会插入文本。例如,您有“这是一个粗体文本片段”,然后您选择“粗体”并将属性更改为粗体。原始元素被分离,出现 3 个新元素。我没有测试它,但它可能会调用 insertUpdate() 和 removeUpdate()
有谁知道 Document.setCharacterAttributes 和 Document.setParagraphAttributes 之间的实际区别?
有段落和字符属性。字符属性包括字体大小、系列、样式、颜色。段落属性有对齐、缩进、行距。
实际上段落是 char 元素的父元素。
You can try to set a flag indicating whether it's user changes or your API changes. In the beginning of the Engine.addDocument() set the flag to API state and reset it back after changes are done.
In your listener check the flag and skip changes from API.
You wrote " I use highlights the text by setting the character attributes of a portion of the Document, so the method is not inserting more text". I'm not sure it doesn't insert text. E.g. you have "it's a bold text piece" then you select the "bold" and change attributes to bold. Original element is separated and 3 new elements appear. I didn't test it but it might call insertUpdate() and removeUpdate()
does anyone know the actual difference between Document.setCharacterAttributes and Document.setParagraphAttributes?
There are paragraph and char attributes. Char attributes are font size, family, style, colors. Paragraph attributes are alignment, indentation, line spacing.
Actually paragraphs are char elements' parents.