Module java.desktop
Package javax.swing.text

Interface Document

所有已知的子接口:
StyledDocument
所有已知的实现类:
AbstractDocument, DefaultStyledDocument, HTMLDocument, PlainDocument

public interface Document

Document 是一个文本容器,作为 Swing 文本组件的模型。这个接口的目标是从非常简单的需求(一个普通文本文本字段)扩展到复杂的需求(例如 HTML 或 XML 文档)。

内容

在最简单的级别上,文本可以被建模为字符的线性序列。为了支持国际化,Swing 文本模型使用 unicode 字符。在文本组件中显示的字符序列通常被称为组件的 内容

为了引用序列中的位置,使用的坐标是两个字符之间的位置。如下图所示,文本文档中的位置可以被称为位置或偏移量。这个位置是从零开始的。

以下文本描述了这个图形。

例如,在一个文档的内容是序列 "The quick brown fox",如前面的图所示,单词 "The" 前面的位置是 0,单词 "The" 后面并在其后的空格之前的位置是 3。序列 "The" 中的所有字符被称为一个 范围

以下方法提供了访问组成内容的字符数据。

结构

文本很少被简单地表示为无特征的内容。相反,文本通常与某种结构相关联。确切的结构模型取决于特定的 Document 实现。它可能是没有结构(即一个简单的文本字段),也可能是像下面的图表所示的东西。

图表显示 Book->Chapter->Paragraph

结构的单元(即树的节点)由 Element 接口引用。每个 Element 可以附带一组属性。这些属性(名称/值对)由 AttributeSet 接口定义。

以下方法提供了访问文档结构的方式。

变异

所有文档都需要能够添加和删除简单文本。通常,文本是通过键盘或鼠标的手势插入和删除的。插入或删除对文档结构的影响完全取决于文档的实现。

以下方法与文档内容的变异相关:

通知

Document 的变异必须通知感兴趣的观察者。变更的通知遵循为 JavaBeans 指定的事件模型准则。在 JavaBeans 事件模型中,一旦事件通知被分派,所有监听器必须在事件源发生进一步变异之前被通知。此外,传递的顺序不能保证。

通知分为两个独立的事件,DocumentEventUndoableEditEvent。如果通过其 api 对 Document 进行变异,将向所有注册的 DocumentListeners 发送一个 DocumentEvent。如果 Document 实现支持撤销/重做功能,则将向所有注册的 UndoableEditListener 发送一个 UndoableEditEvent。如果撤销可编辑,则应从文档中触发一个 DocumentEvent,以指示它再次发生了变化。但在这种情况下,不应生成 UndoableEditEvent,因为该编辑实际上是变化的源,而不是通过其 api 对 Document 进行的变异。

前面的文本描述了这个图形。

参考上面的图表,假设左侧显示的组件变异了由蓝色矩形表示的文档对象。文档会向组件视图分派一个 DocumentEvent,并向维护历史缓冲区的监听逻辑发送一个 UndoableEditEvent。

现在假设右侧显示的组件变异了相同的文档。同样,文档会向组件视图分派一个 DocumentEvent,并向维护历史缓冲区的监听逻辑发送一个 UndoableEditEvent。

如果历史缓冲区被回滚(即撤销最后的 UndoableEdit),则会向两个视图发送一个 DocumentEvent,使它们都反映对文档的撤销变异(即删除右侧组件的变异)。如果历史缓冲区再次回滚另一个更改,将向两个视图发送另一个 DocumentEvent,使它们反映对文档的撤销变异(即删除左侧组件的变异)。

与观察文档变异相关的方法包括:

属性

文档实现通常在运行时与一些属性相关联。两个众所周知的属性是 StreamDescriptionProperty,可用于描述 Document 的来源,以及 TitleProperty,可用于命名 Document。与属性相关的方法包括:

概述和编程提示

Element 是构建文档时使用的重要接口。它有能力描述文档的各种结构部分,如段落、文本行,甚至(在 HTML 文档中)列表中的项目。从概念上讲,Element 接口捕捉了 SGML 文档的一些精神。因此,如果您了解 SGML,您可能已经对 Swing 的 Element 接口有一些了解。

在 Swing 文本 API 的文档模型中,Element 接口定义了文档的结构部分,如段落、文本行或 HTML 文档中的列表项。

每个 Element 要么是一个 分支,要么是一个 叶子。如果一个元素是一个分支,isLeaf() 方法返回 false。如果一个元素是一个叶子,isLeaf() 返回 true。

分支可以有任意数量的子元素。叶子没有子元素。要确定分支有多少子元素,可以调用 getElementCount()。要确定 Element 的父级,可以调用 getParentElement()。根元素没有父级,因此在根上调用 getParentElement() 将返回 null。

Element 表示文档中的特定区域,从 startOffset 开始,结束于 endOffset 前。分支 Element 的起始偏移量通常是其第一个子元素的起始偏移量。类似地,分支 Element 的结束偏移量通常是其最后一个子元素的结束偏移量。

每个 Element 都关联一个 AttributeSet,可以通过调用 getAttributes() 访问。在 Element 中,AttributeSet 本质上是一组键/值对。这些对通常用于标记 -- 例如确定 Element 的前景色、字体大小等。但是,存储在 AttributeSet 中的内容由模型和开发人员确定。

您可以通过调用 Document 接口中定义的方法 getDefaultRootElement()getRootElements() 来获取文档的根 Element(或 Elements)。

Document 接口负责将字符的线性视图转换为 Element 操作。每个 Document 实现定义 Element 结构是什么。

PlainDocument 类

PlainDocument 类定义了一个 Element 结构,其中根节点有每行文本模型的子节点。 图 1 显示了两行文本如何由 PlainDocument 建模

前面的文本描述了这个图形。

图 2 显示了这两行文本如何映射到实际内容:

前面的文本描述了这个图形。

向 PlainDocument 插入文本

正如刚才提到的,PlainDocument 包含一个根 Element,该根 Element 包含每行文本的 Element。当文本插入到 PlainDocument 中时,它会为每个换行符创建所需的 Element。举例来说,假设您想要在 图 2 中的偏移量 2 处插入一个换行符。为了实现这个目标,您可以使用 Document 方法 insertString(),使用以下语法:

document.insertString(2, "\n", null);

调用 insertString() 方法后,Element 结构将如 图 3 所示。

前面的文本描述了这个图形。

举个例子,假设您想要在 图 2 中的偏移量 2 处插入模式 "new\ntext\n"。这个操作将产生 图 4 中所示的结果。

前面的文本描述了这个图形。

在前面的示例中,插入后行 Element 的名称更改以匹配行号。但请注意,当这样做时,AttributeSets 保持不变。例如,在 图 2 中,第 2 行的 AttributeSet 与 图 4 中第 4 行的 AttributeSet 匹配。

从 PlainDocument 中删除文本

删除文本会导致结构变化,如果删除跨越多行。考虑在前面显示的图3中从偏移量1开始的七个字符的删除。在这种情况下,代表第2行的元素被完全移除,因为它代表的区域包含在被删除的区域中。代表第1行和第3行的元素被合并,因为它们部分包含在被删除的区域中。因此,我们得到以下结果:

前文描述了这个图形。

默认的StyledDocument类

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

前文描述了这个图形。

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

前文描述了这个图形。

向DefaultStyledDocument插入文本

如前所述,DefaultStyledDocument维护一个元素结构,根元素包含每个段落的子元素。依次,每个段落元素包含段落中每种文本样式的元素。举个例子,假设您有一个包含一个段落的文档,这个段落包含两种样式,如图8所示。

前文描述了这个图形。

insertString()方法,如下所示:

 styledDocument.insertString(2, "\n",
                styledDocument.getCharacterElement(0).getAttributes());
图9中显示的结果。

前文描述了这个图形。

insertString()的属性集与样式1的属性相匹配。如果传递给 insertString()的属性集不匹配,结果将是 图10中显示的情况。

前文描述了这个图形。

从DefaultStyledDocument中删除文本

图11所示。

前文描述了这个图形。

图12中显示的结果。

前文描述了这个图形。

StyledDocument类

StyledDocument类提供了一个名为setCharacterAttributes()的方法,允许您在给定范围内设置字符元素的属性:

 public void setCharacterAttributes
          (int offset, int length, AttributeSet s, boolean replace);
setCharacterAttributes()方法可以用于设置它们的属性。

setCharacterAttributes()方法接受四个参数。第一个和第二个参数标识要更改的文档中的区域。第三个参数指定新属性(作为AttributeSet),第四个参数确定新属性是否应添加到现有属性中(值为false),还是字符元素应该用新属性替换其现有属性(值为true)。

图9中的前三个字符的属性。传递给 setCharacterAttributes()的前两个参数将是0和3。第三个参数将是包含新属性的AttributeSet。在我们考虑的示例中,第四个参数是无关紧要的。

图9中显示的前三个字符,而是更改前两个字符。因为结束更改偏移量(2)不落在字符元素边界上,所以必须以这样的方式拆分偏移量2的元素,使得偏移量2是两个元素的边界。调用 setCharacterAttributes(),起始偏移量为0,长度为2,结果如前面在 图10中显示。

在StyledDocument中更改段落属性

setParagraphAttributes()的方法,可用于更改段落元素的属性:

 public void setParagraphAttributes
         (int offset, int length, AttributeSet s, boolean replace);
setCharacterAttributes(),但它允许您更改段落元素的属性。StyledDocument的实现定义哪些元素是段落。DefaultStyledDocument将段落元素解释为字符元素的父元素。调用此方法不会导致结构更改;只有段落元素的属性会更改。

EditorKitView。View负责呈现特定元素,而EditorKit负责ViewFactory,根据元素决定应创建哪个View。

参见:
  • Field Details

    • StreamDescriptionProperty

      static final String StreamDescriptionProperty
      用于初始化文档的流的描述的属性名称。如果文档是从流初始化的,并且了解流的任何信息,则应使用此属性。
      参见:
    • TitleProperty

      static final String TitleProperty
      如果有标题,文档的标题的属性名称。
      参见:
  • Method Details

    • getLength

      int getLength()
      返回当前文档中的内容字符数。
      返回:
      字符数 >= 0
    • addDocumentListener

      void addDocumentListener(DocumentListener listener)
      注册给定的观察者以开始接收文档更改时的通知。
      参数:
      listener - 要注册的观察者
      参见:
    • removeDocumentListener

      void removeDocumentListener(DocumentListener listener)
      从通知列表中注销给定的观察者,以便不再接收更改更新。
      参数:
      listener - 要注册的观察者
      参见:
    • addUndoableEditListener

      void addUndoableEditListener(UndoableEditListener listener)
      注册给定的观察者以开始接收可撤销编辑时的通知。
      参数:
      listener - 要注册的观察者
      参见:
    • removeUndoableEditListener

      void removeUndoableEditListener(UndoableEditListener listener)
      从通知列表中注销给定的观察者,以便不再接收更新。
      参数:
      listener - 要注册的观察者
      参见:
    • getProperty

      Object getProperty(Object key)
      获取与文档关联的属性。
      参数:
      key - 非null的属性键
      返回:
      属性
      参见:
    • putProperty

      void putProperty(Object key, Object value)
      将属性与文档关联。提供的两个标准属性键是: StreamDescriptionPropertyTitleProperty。还可以定义其他属性,例如作者。
      参数:
      key - 非null的属性键
      value - 属性值
      参见:
    • remove

      void remove(int offs, int len) throws BadLocationException
      插入内容字符串。这将导致发送类型为DocumentEvent.EventType.INSERT的DocumentEvent到已注册的DocumentListers,除非抛出异常。通过调用DocumentListener上的insertUpdate方法来传递DocumentEvent。生成的DocumentEvent的偏移量和长度将指示实际对文档进行了什么更改。

      图表显示在'The quick brown fox'中插入'quick'

      如果文档结构因插入而更改,则响应更改插入的元素和删除的详细信息也将包含在生成的DocumentEvent中。文档的实现决定如何响应插入时结构应如何更改。

      如果文档支持撤销/重做,则还将生成UndoableEditEvent。

      Parameters:
      offs - the offset from the beginning >= 0
      len - the number of characters to remove >= 0
      Throws:
      BadLocationException - some portion of the removal range was not a valid part of the document. The location in the exception is the first bad position encountered.
      See Also:
    • insertString

      void insertString(int offset, String str, AttributeSet a) throws BadLocationException
      Inserts a string of content. This will cause a DocumentEvent of type DocumentEvent.EventType.INSERT to be sent to the registered DocumentListers, unless an exception is thrown. The DocumentEvent will be delivered by calling the insertUpdate method on the DocumentListener. The offset and length of the generated DocumentEvent will indicate what change was actually made to the Document.

      Diagram shows insertion of 'quick' in 'The quick brown fox'

      If the Document structure changed as result of the insertion, the details of what Elements were inserted and removed in response to the change will also be contained in the generated DocumentEvent. It is up to the implementation of a Document to decide how the structure should change in response to an insertion.

      If the Document supports undo/redo, an UndoableEditEvent will also be generated.

      参数:
      offset - 插入内容的文档偏移量 >= 0。所有在给定位置之后或之后跟踪更改的位置都将移动。
      str - 要插入的字符串
      a - 与插入内容关联的属性。如果没有属性,则可能为null。
      抛出:
      BadLocationException - 给定的插入位置不是文档中的有效位置
      参见:
    • getText

      String getText(int offset, int length) throws BadLocationException
      获取文档中给定部分包含的文本。
      参数:
      offset - 表示所需文本起始位置的文档偏移量 >= 0
      length - 所需字符串的长度 >= 0
      返回:
      文本,长度 >= 0 的字符串
      抛出:
      BadLocationException - 给定范围的某些部分不是文档的有效部分。异常中的位置是遇到的第一个错误位置。
    • getText

      void getText(int offset, int length, Segment txt) throws BadLocationException
      获取文档中给定部分包含的文本。

      如果txt参数上的partialReturn属性为false,则Segment中返回的数据将是请求的整个长度,具体取决于数据的存储方式,可能是副本,也可能不是。如果partialReturn属性为true,则只返回可以在不创建副本的情况下返回的文本量。对于需要扫描文档大部分内容的情况,使用部分返回将提供更好的性能。以下是使用部分返回访问整个文档的示例:

      
      
         int nleft = doc.getDocumentLength();
         Segment text = new Segment();
         int offs = 0;
         text.setPartialReturn(true);
         while (nleft > 0) {
             doc.getText(offs, nleft, text);
             // 处理文本
             nleft -= text.count;
             offs += text.count;
         }
      
       
      参数:
      offset - 表示所需文本起始位置的文档偏移量 >= 0
      length - 所需字符串的长度 >= 0
      txt - 用于返回文本的Segment对象
      抛出:
      BadLocationException - 给定范围的某些部分不是文档的有效部分。异常中的位置是遇到的第一个错误位置。
    • getStartPosition

      Position getStartPosition()
      返回表示文档开头的位置。返回的位置可以被视为跟踪更改并始终位于文档开头的位置。
      返回:
      位置
    • getEndPosition

      Position getEndPosition()
      返回表示文档结尾的位置。返回的位置可以被视为跟踪更改并始终位于文档结尾的位置。
      返回:
      位置
    • createPosition

      Position createPosition(int offs) throws BadLocationException
      此方法允许应用程序标记字符内容序列中的位置。然后,可以使用此标记来跟踪插入和删除操作时的更改。策略是插入始终发生在当前位置之前(最常见的情况),除非插入位置为零,在这种情况下,插入将被强制到跟随原始位置的位置。
      参数:
      offs - 距离文档开头的偏移量 >= 0
      返回:
      位置
      抛出:
      BadLocationException - 如果给定位置不表示关联文档中的有效位置
    • getRootElements

      Element[] getRootElements()
      返回定义的所有根元素。

      通常只会有一个文档结构,但接口支持在文本数据上构建任意数量的结构投影。文档可以具有多个根元素以支持多个文档结构。一些示例可能包括:

      • 文本方向。
      • 词法标记流。
      • 解析树。
      • 转换为非本机格式。
      • 修改规范。
      • 注释。
      返回:
      根元素
    • getDefaultRootElement

      Element getDefaultRootElement()
      返回应基于的根元素,除非提供了其他分配视图给元素结构的机制。
      返回:
      根元素
    • render

      void render(Runnable r)
      如果模型支持异步更新,则允许模型在并发存在的情况下安全地呈现。给定的runnable将以允许其在执行期间安全地读取模型而不进行任何更改的方式执行。runnable本身可能 进行任何变更。
      参数:
      r - 用于呈现模型的Runnable