- 所有已知的子接口:
StyledDocument
- 所有已知的实现类:
AbstractDocument,DefaultStyledDocument,HTMLDocument,PlainDocument
Document 是一个文本容器,用作 swing 文本组件的模型。此接口的目标是从非常简单的需求(纯文本文本字段)扩展到复杂的需求(例如 HTML 或 XML 文档)。
内容
在最简单的层面上,文本可以建模为字符的线性序列。为了支持国际化,Swing 文本模型使用了 Unicode 个字符。文本组件中显示的字符序列通常称为组件的 content 。
为了引用序列中的位置,使用的坐标是两个字符之间的位置。如下图所示,文本文档中的位置可以称为位置或偏移量。这个职位是从零开始的。

在示例中,如果文档的内容是序列“The quick brown fox”,如上图所示,则单词“The”之前的位置为 0,单词“The”之后和之前的位置它后面的空格是 3。序列“The”中的整个字符序列称为 range。
以下方法可以访问构成内容的字符数据。
结构
文本很少简单地表示为无特征的内容。相反,文本通常具有某种与之关联的结构。究竟建模什么结构取决于特定的文档实现。它可能像没有结构一样简单(即一个简单的文本字段),也可能类似于下图。

结构单元(即树的一个节点)由Element 接口引用。每个元素都可以用一组属性来标记。这些属性(名称/值对)由AttributeSet 接口定义。
以下方法可以访问文档结构。
突变
所有文档都需要能够添加和删除简单文本。通常,文本是通过键盘或鼠标的手势插入和删除的。插入或删除对文档结构的影响完全取决于文档的实现。
以下方法与文档内容的变异有关:
insertString(int, java.lang.String, javax.swing.text.AttributeSet)remove(int, int)createPosition(int)
Notification
Document 的突变必须传达给感兴趣的观察者。更改通知遵循为 JavaBeans 指定的事件模型准则。在 JavaBeans 事件模型中,一旦事件通知被分派,所有监听器都必须在事件源发生任何进一步的变化之前得到通知。此外,不能保证交货顺序。
通知作为两个单独的事件提供,DocumentEvent 和 UndoableEditEvent。如果通过其 api 对 Document 进行了更改,则 DocumentEvent 将发送到所有已注册的 DocumentListeners 。如果 Document 实现支持撤消/重做功能,则 UndoableEditEvent 将发送到所有已注册的 UndoableEditListener s。如果撤消了可撤消的编辑,则应从文档中触发 DocumentEvent 以指示它已再次更改。然而,在这种情况下,不应生成 UndoableEditEvent,因为该编辑实际上是更改的来源,而不是通过其 api 对 Document 进行的突变。

参考上图,假设左边显示的组件改变了蓝色矩形表示的文档对象。文档通过向两个组件视图分派一个 DocumentEvent 并将一个 UndoableEditEvent 发送到监听逻辑来响应,监听逻辑维护一个历史缓冲区。
现在假设右边显示的组件改变了同一个文档。同样,文档将 DocumentEvent 分派给两个组件视图,并将 UndoableEditEvent 发送给维护历史缓冲区的监听逻辑。
如果历史缓冲区随后被回滚(即最后一个 UndoableEdit 撤消),一个 DocumentEvent 被发送到两个视图,导致它们都将撤消的变更反映到文档(即,删除正确组件的变更)。如果历史缓冲区再次回滚另一个更改,则会将另一个 DocumentEvent 发送到两个视图,使它们将未完成的更改反映到文档中——也就是说,删除左侧组件的更改。
与观察文档突变相关的方法有:
addDocumentListener(DocumentListener)removeDocumentListener(DocumentListener)addUndoableEditListener(UndoableEditListener)removeUndoableEditListener(UndoableEditListener)
Properties
文档实现通常会在运行时有一些与之关联的属性集。两个众所周知的属性是 StreamDescriptionProperty ,可用于描述 Document 来自何处,以及 TitleProperty ,可用于命名 Document 。与属性相关的方法有:
概述和编程技巧
Element 是用于构建文档的重要接口。它能够描述文档的各种结构部分,例如段落、文本行,甚至(在 HTML 文档中)列表中的项目。从概念上讲,Element 接口捕捉了 SGML 文档的一些精神。所以如果你了解 SGML,你可能已经对 Swing 的 Element 接口有了一些了解。
在 Swing 文本 API 的文档模型中,接口元素定义了文档的一个结构部分,例如 HTML 文档中的一个段落、一行文本或一个列表项。
每个元素要么是branch或叶子.如果元素是分支,isLeaf() 方法返回 false。如果元素是叶子,isLeaf() 返回 true。
分支可以有任意数量的孩子。叶子没有孩子。要确定一个分支有多少个孩子,您可以调用 getElementCount() 。要确定元素的父级,您可以调用 getParentElement() 。根元素没有父元素,因此在根上调用 getParentElement() 会返回 null。
元素表示文档中以 startOffset 开始并恰好在 endOffset 之前结束的特定区域。分支元素的起始偏移量通常是其第一个子元素的起始偏移量。同样,分支元素的结束偏移量通常是其最后一个子元素的结束偏移量。
每个元素都与一个 AttributeSet 相关联,您可以通过调用 getAttributes() 来访问它。在一个 Element 中,AttributeSet 本质上是一组键/值对。这些对通常用于标记——例如确定元素的前景色、字体大小等。但由模型和开发人员决定 AttributeSet 中存储的内容。
您可以通过调用 Document 接口中定义的方法 getDefaultRootElement() 和 getRootElements() 来获取 Document 的根元素(或多个元素)。
Document 接口负责将字符的线性视图转换为 Element 操作。由每个 Document 实现来定义 Element 结构是什么。
纯文档类
这PlainDocument 类定义了一个 Element 结构,其中根节点对于模型中的每一行文本都有一个子节点。图1显示两行文本将如何由 PlainDocument 建模

图 2显示相同的两行文本如何映射到实际内容:

将文本插入 PlainDocument
正如刚才提到的,一个 PlainDocument 包含一个根元素,而根元素又包含一个对应于每一行文本的元素。当文本被插入到 PlainDocument 中时,它会创建每个换行符存在的元素所需的元素。为了说明,假设您想在偏移量 2 处插入一个换行符图 2, 多于。要实现此目标,您可以使用 Document 方法 insertString(),使用以下语法:
document.insertString(2, "\n", null);
调用 insertString() 方法后,元素结构将如下图所示图 3.

作为另一个示例,假设您想要在偏移量 2 处插入模式“new\ntext\n”,如前文所示图 2.此操作的结果显示在图 4.

在前面的insets中,行元素的名称在插入后更改以匹配行号。但请注意,完成此操作后,AttributeSets 保持不变。例如,在图 2,第 2 行的 AttributeSet 与第 4 行的 AttributeSet 匹配图 4.
从 PlainDocument 中删除文本
如果删除超过一行,则删除文本会导致结构更改。考虑删除前面显示的从偏移量 1 开始的七个字符图 3.在这种情况下,表示第 2 行的元素被完全删除,因为它表示的区域包含在删除的区域中。表示第 1 行和第 3 行的元素已连接,因为它们部分包含在已删除的区域中。因此,我们得到了结果:

默认的 StyledDocument 类
这DefaultStyledDocument 类,用于样式文本,包含另一个级别的元素。需要这个额外的级别,以便每个段落可以包含不同样式的文本。在所示的两段中图 6,第一段包含两种样式,第二段包含三种样式。

图 7展示了这些相同的元素如何映射到内容。

将文本插入 DefaultStyledDocument
如前所述,DefaultStyledDocument 维护一个元素结构,以便根元素包含每个段落的子元素。反过来,这些段落元素中的每一个都包含段落中每种文本样式的元素。例如,假设您有一个包含一个段落的文档,并且该段落包含两种样式,如下所示图 8.

如果您随后想在偏移量 2 处插入换行符,您将再次使用方法 insertString() ,如下所示:
styledDocument.insertString(2, "\n",
styledDocument.getCharacterElement(0).getAttributes());
此操作的结果显示在图 9.

需要注意的是,传递给insertString()的AttributeSet与Style 1的属性相匹配。如果传递给insertString()的AttributeSet不匹配,结果将是如图所示的情况图 10.

从 DefaultStyledDocument 中删除文本
从 DefaultStyledDocument 中删除文本类似于从 PlainDocument 中删除文本。唯一的区别是元素的额外级别。考虑一下如果您删除上面图 10 中偏移量 1 处的两个字符会发生什么。由于第 1 段的第二个要素完全包含在删除的区域中,因此将被删除。假设 Paragraph 1 的第一个子项的属性与 Paragraph2 的第一个子项的属性相匹配,结果将显示在图 11.

如果属性不匹配,我们将得到如下所示的结果图 12.

StyledDocument 类
这StyledDocument class 提供了一个名为 setCharacterAttributes() 的方法,它允许您在给定范围内设置字符元素上的属性:
public void setCharacterAttributes
(int offset, int length, AttributeSet s, boolean replace);
回想一下,在上一节中显示的图表中,图中显示的所有叶子元素也是字符元素。这意味着可以使用 setCharacterAttributes() 方法来设置它们的属性。
setCharacterAttributes() 方法有四个参数。第一个和第二个参数标识文档中要更改的区域。第三个参数指定新属性(作为 AttributeSet),第四个参数确定是否应将新属性添加到现有属性(值为 false)或字符元素是否应将其现有属性替换为新属性(真值)。
例如,假设您想更改中前三个字符的属性图 9,如前所示。传递给 setCharacterAttributes() 的前两个参数是 0 和 3。第三个参数是包含新属性的 AttributeSet。在我们正在考虑的示例中,第四个参数是什么并不重要。
由于更改区域(0 和 3)的开始和结束偏移量落在字符元素边界上,因此不需要更改结构。也就是说,只有字符元素样式 1 的属性会发生变化。
现在让我们看一个需要改变结构的示例。而不是更改中显示的前三个字符图 9, 让我们改变前两个字符。由于结束变化偏移量 (2) 不落在字符元素边界上,因此必须以偏移量 2 为两个元素边界的方式拆分偏移量 2 处的元素。以起始偏移量 0 和长度 2 调用 setCharacterAttributes() 的结果显示在前面图 10.
更改 StyledDocument 中的段落属性
StyledDocument 类提供了一个名为 setParagraphAttributes() 的方法,可用于更改段落元素的属性:
public void setParagraphAttributes
(int offset, int length, AttributeSet s, boolean replace);
此方法类似于 setCharacterAttributes() ,但它允许您更改段落元素的属性。由 StyledDocument 的实现来定义哪些元素是段落。 DefaultStyledDocument 将段落元素解释为字符元素的父元素。调用此方法不会导致结构更改;只有段落元素的属性发生变化。
建议查看 EditorKit 和 View 。 View 负责渲染特定的 Element,而 EditorKit 负责一个 ViewFactory,它能够根据 Element 决定应该创建什么 View。
- 参见:
-
字段摘要
字段 -
方法总结
修饰符和类型方法描述voidaddDocumentListener(DocumentListener listener) 注册给定的观察者以在对文档进行更改时开始接收通知。voidaddUndoableEditListener(UndoableEditListener listener) 注册给定的观察者以在对文档进行可撤消的编辑时开始接收通知。createPosition(int offs) 此方法允许应用程序在字符内容序列中标记一个位置。返回视图应该基于的根元素,除非提供了一些其他的将视图分配给元素结构的机制。返回表示文档结尾的位置。int返回文档中当前内容的字符数。getProperty(Object key) 获取与文档关联的属性。Element[]返回所有定义的根元素。返回表示文档开头的位置。getText(int offset, int length) 获取文档给定部分中包含的文本。void获取文档给定部分中包含的文本。voidinsertString(int offset, String str, AttributeSet a) 插入一串内容。voidputProperty(Object key, Object value) 将属性与文档相关联。voidremove(int offs, int len) 删除文档的一部分内容。voidremoveDocumentListener(DocumentListener listener) 从通知列表中取消注册给定的观察者,因此它将不再接收更改更新。void从通知列表中取消注册给定的观察者,因此它将不再接收更新。void如果模型支持异步更新,则允许模型在并发情况下安全呈现。
-
字段详细信息
-
StreamDescriptionProperty
用于初始化文档的流描述的属性名称。如果文档是从流初始化的并且关于该流的任何信息都是已知的,则应该使用它。- 参见:
-
TitleProperty
文档标题的属性名称(如果有的话)。- 参见:
-
-
方法详情
-
getLength
int getLength()返回文档中当前内容的字符数。- 返回:
- 字符数 >= 0
-
addDocumentListener
注册给定的观察者以在对文档进行更改时开始接收通知。- 参数:
listener- 要注册的观察者- 参见:
-
removeDocumentListener
从通知列表中取消注册给定的观察者,因此它将不再接收更改更新。- 参数:
listener- 要注册的观察者- 参见:
-
addUndoableEditListener
注册给定的观察者以在对文档进行可撤消的编辑时开始接收通知。- 参数:
listener- 要注册的观察者- 参见:
-
removeUndoableEditListener
从通知列表中取消注册给定的观察者,因此它将不再接收更新。- 参数:
listener- 要注册的观察者- 参见:
-
getProperty
获取与文档关联的属性。- 参数:
key- 一个非null属性键- 返回:
- 属性
- 参见:
-
putProperty
将属性与文档相关联。提供的两个标准属性键是:StreamDescriptionProperty和TitleProperty。还可以定义其他属性,例如作者。- 参数:
key- 非null属性键value- 属性值- 参见:
-
remove
删除文档的一部分内容。这将导致将类型为 DocumentEvent.EventType.REMOVE 的 DocumentEvent 发送到已注册的 DocumentListener,除非抛出异常。通知将通过调用 DocumentListeners 上的 removeUpdate 方法发送给监听。为了确保在并发情况下的合理行为,事件在发生变化后被分派。这意味着在发送删除通知时,文档已经更新并且
createPosition创建的任何标记都已经更改。对于删除,删除范围的末尾折叠到范围的开头,删除范围内的任何标记都折叠到范围的开头。
如果 Document 结构因删除而更改,则响应更改而插入和删除的元素的详细信息也将包含在生成的 DocumentEvent 中。由文档的实现来决定结构应该如何更改以响应删除。
如果Document支持undo/redo,也会产生一个UndoableEditEvent。
- 参数:
offs- 从开始的偏移量 >= 0len- 要删除的字符数 >= 0- 抛出:
BadLocationException- 删除范围的某些部分不是文档的有效部分。异常中的位置是遇到的第一个坏位置。- 参见:
-
insertString
插入一串内容。这将导致将 DocumentEvent.EventType.INSERT 类型的 DocumentEvent 发送到已注册的 DocumentListers,除非抛出异常。 DocumentEvent 将通过调用 DocumentListener 上的 insertUpdate 方法来传递。生成的 DocumentEvent 的偏移量和长度将指示实际对 Document 进行了哪些更改。
如果 Document 结构因插入而更改,则响应更改而插入和删除哪些元素的详细信息也将包含在生成的 DocumentEvent 中。由 Document 的实现来决定结构应如何更改以响应插入。
如果Document支持undo/redo,也会产生一个UndoableEditEvent。
- 参数:
offset- 文档中插入内容的偏移量 >= 0。在给定位置处或之后跟踪更改的所有位置都将移动。str- 要插入的字符串a- 与插入内容关联的属性。如果没有属性,这可能为 null。- 抛出:
BadLocationException- 给定的插入位置不是文档中的有效位置- 参见:
-
getText
获取文档给定部分中包含的文本。- 参数:
offset- 文档中表示所需文本开头的偏移量 >= 0length- 所需字符串的长度 >= 0- 返回:
- 文本,在长度 >= 0 的字符串中
- 抛出:
BadLocationException- 给定范围的某些部分不是文档的有效部分。异常中的位置是遇到的第一个坏位置。
-
getText
获取文档给定部分中包含的文本。如果 txt 参数的 partialReturn 属性为 false,则 Segment 中返回的数据将是请求的整个长度,并且可能是也可能不是副本,具体取决于数据的存储方式。如果 partialReturn 属性为真,则只返回无需创建副本即可返回的文本量。在扫描大部分文档的情况下,使用部分返回会提供更好的性能。以下是使用部分返回访问整个文档的示例:
int nleft = doc.getDocumentLength(); Segment text = new Segment(); int offs = 0; text.setPartialReturn(true); while (nleft > 0) { doc.getText(offs, nleft, text); // do something with text nleft -= text.count; offs += text.count; }- 参数:
offset- 文档中表示所需文本开头的偏移量 >= 0length- 所需字符串的长度 >= 0txt- 返回文本的 Segment 对象- 抛出:
BadLocationException- 给定范围的某些部分不是文档的有效部分。异常中的位置是遇到的第一个坏位置。
-
getStartPosition
Position getStartPosition()返回表示文档开头的位置。可以依靠返回的位置来跟踪更改并保持在文档的开头。- 返回:
- 位置
-
getEndPosition
Position getEndPosition()返回表示文档结尾的位置。可以依靠返回的位置来跟踪更改并保持在文档末尾。- 返回:
- 位置
-
createPosition
此方法允许应用程序在字符内容序列中标记一个位置。当在内容中进行插入和删除时,此标记可用于跟踪更改。策略是插入始终发生在当前位置之前(最常见的情况),除非插入位置为零,在这种情况下,插入被强制到原始位置之后的位置。- 参数:
offs- 从文档开始的偏移量 >= 0- 返回:
- 位置
- 抛出:
BadLocationException- 如果给定位置不代表相关文档中的有效位置
-
getRootElements
Element [] getRootElements()返回所有定义的根元素。通常只有一种文档结构,但界面支持在文本数据上构建任意数量的结构投影。文档可以有多个根元素以支持多种文档结构。一些示例可能是:
- 文字方向。
- 词法标记流。
- 解析树。
- 转换为本机格式以外的格式。
- 改装规范。
- 注释。
- 返回:
- 根元素
-
getDefaultRootElement
Element getDefaultRootElement()返回视图应该基于的根元素,除非提供了一些其他的将视图分配给元素结构的机制。- 返回:
- 根元素
-
render
如果模型支持异步更新,则允许模型在并发情况下安全呈现。给定的 runnable 将以允许它在执行 runnable 时安全地读取模型而无需更改的方式执行。 runnable 本身可以not 进行任何更改。- 参数:
r- 用于渲染模型的Runnable
-