MS Word中将范围附加到文档的功能

5
假设我想在文档末尾添加一些文本,并立即将其作为Range对象访问,以便可以设置它的一些属性而不影响前面的文本。理想情况下, Range.InsertAfter 方法将返回一个Range对象,这对于此非常完美,但实际上并不是这样。 Word肯定知道插入InsertAfter后定义的范围,但在表面上,我需要根据插入文本的长度“事后”计算它,或以其他方式计算。
因此,我设计了一个简单的解决方法。用伪代码(实际上是Delphi代码,但我希望这不会阻止VBA答案)来表示,我的操作如下:
ARange := Document.Range
ARange.Text := 'AAA'

AEnd := ARange.End - 1        // AEnd is an integer
ARange.SetRange(AEnd, AEnd)
ARange.Text := 'XXX'
ARange.Bold := True

看起来我可以通过重复第二个代码块的方式无限地在文档末尾添加文本块。

这行代码

ARange.SetRange(AEnd, AEnd)

据我理解,使用insertNode方法似乎可以在现有范围的末尾构建一个新的范围(不像在现有范围上调用Collapse方法)。我已经尝试了一些简单的测试用例,效果很好。但这让我想知道是否有更直接的方法将范围添加到文档并获取对其的引用?
附注:我应该更清楚地表明,我正在尝试在没有使用Selection对象的情况下完成此操作(出于各种原因,包括每次只能有一个Selection对象)。

感谢@KenWhite。我应该提到我试图避免使用Selection,因为Cindy Meister在这里最近发表了一条评论(她似乎是一位Word专家和专家)。 - MartynA
4个回答

5

有多种方法可以获得文档末尾的区域范围。您已经发现了一种方法,但是正如您所说,这有些绕弯子。我更喜欢的方法:

Word.Range rngEndOfDoc = Document.Content; 
//Content returns a Range object and is a property, not a method like Range()
rngEndOfDoc.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
rngEndOfDoc.Text = "Text at the end of the document";

折叠范围的概念类似于在选择文本时按下右(或左)箭头键。因此,rngEndOfDoc变成了一个“点”,而不是包含整个文档主体内容的范围。

顺便说一句,我从未想过在何种情况下会使用EndKey(模拟用户操作),只有当我想将用户留在文档末尾以便他可以从该位置开始输入时,我才会更改选择。


在 Delphi 开发时,它可以自动化文档本身。用户不需要参与;这不是用户将从 Word 中运行的 VBA 宏。在通过编程方式创建文档时移动选择是可以的,并且使用 EndKey 也是可以的。 - Ken White
2
@KenWhite。实际上并不是这样的,它不如使用Range高效。即使用户没有与文档交互,Word也必须更改光标在文档中的位置。如果文档窗口不可见,则选择可能会很棘手,因为Word确实依赖于“物理”页面布局来完成某些操作。选择本质上是不可预测的,尽管我承认在当前故事的EndKey情况下,您可能会到达您期望的位置。但是,如果有替代选择Selection的方法,尽可能避免使用它。 - Cindy Meister
这是你的个人喜好。使用选择很容易,对于大多数需求来说速度也足够快。我用它来自动化一些文档生成,对我的需求来说性能也足够好。如果你有其他偏好,那是你的选择;这并不意味着使用它是错误的。 - Ken White
1
@CindyMeister:谢谢,我很高兴我的问题引起了你的注意,因为我最近在跟进你对我的答案的评论。当我看到你的代码时,我期望紧接着调用.Bold := True会使整个文本,包括插入点上面的文本变粗体,因为这是我之前实验的结果。但也许我搞混了,因为仅使用你的代码只有插入的部分是加粗的。我将回溯并尝试找出我的混淆出现在哪里。 - MartynA
顺便说一下,我已经给这三个答案点了赞,但我选择接受这个答案是因为它最接近我的起点。不过我仍然希望InsertAfter/InsertBefore返回一个范围;=) - MartynA
显示剩余2条评论

3
感谢其他人提供的三个出色的答案,我想再加上我的。以下是两个函数的版本,它们最初是我希望Word本机提供的,返回一个追加范围。
第一个版本使用传统上随Delphi(例如Word2000.Pas)附带的MS Word Type Library导入单元中的MS Word对象,并使用“早期绑定”自动化,而第二个版本使用后期绑定执行同样的操作。
function AppendRange(InputRange : Range) : Range;
var
  Direction : OleVariant;
begin
  Result := InputRange;
  Direction := wdCollapseEnd;
  Result.Collapse(Direction);
end;

function AppendRangeLB(InputRange : OleVariant) : OleVariant;
begin
  Result := InputRange;
  Result.Collapse(wdCollapseEnd);
end;

使用示例:

AppendedRange := AppendRange(ExistingRange);
AppendedRange.Text := 'YYY';

你知道吗?这本身就是一项有价值的贡献。StackOverflow允许你发布一个问题并自己回答,作为该网站问答概念的贡献。也许更合理的做法是先提出具体问题,然后将上述内容作为答案发布,并标记它为最佳答案 :-) - Cindy Meister
@ CindyMeister:谢谢你的回答,虽然我有点紧张回答自己的问题,感觉就像是和自己说话,这可能是... 不过,说真的,我会尝试用稍微复杂一些的版本回答,使用 Delphi 添加的语言功能(如果我能让它正常工作的话,这将是一个有趣的小项目)。完成后我会联系你。 - MartynA

2
Document.Range视为主文档中所有可能范围的联合(即除标题、页眉、浮动内容等之外)。它始终在第一个字符之前开始,在最后一个字符之后结束(根据我的经验,这通常是一个隐藏的段落标记)。不可能定义另一个范围,该范围位于当前Document.Range之后或在概念上“附加”任何内容在Document.Range之后,因为没有“在Document.Range之后”,它总是延伸到末尾。
因此,要使用新文本或其他内嵌对象扩展文档,必须将它们插入到Document.Range的末尾 - 实际上是在末尾之前,因为最后一个隐藏的段落标记仍必须是文档的最后一个字符。这正是您在伪代码中所做的操作。 在VBA中,可以使用空范围引用文档末尾。
Document.Range(Document.Range.End-1, Document.Range.End-1)

尝试在Document.Range.End处定义它实际上会引发错误,因为它指向最后一个(隐藏的)字符之后 - 这超出了文档范围 - 这就是为什么我们需要“-1”的原因。
获取此范围后,我们可以用内容填充它 - 扩展它并逻辑上扩展Document.Range。例如,在活动文档的末尾添加文本,可以编写以下代码。
ActiveDocument.Range(ActiveDocument.Range.End-1, ActiveDocument.Range.End-1).Text = "New Text"

请注意,可以使用以下方式达到相同的“最终”空范围:
Document.Bookmarks("\EndOfDoc").Range

1
谢谢:“因为没有文档范围之后的内容”。是的,好观点,加一。 “试图在Document.Range.End处定义它”:奇怪,因为它对我有效,让我尝试在我的代码中使用.End - 1… - MartynA
1
哦,我明白了...那是因为你使用了 Range.SetRange。这个方法会自动将其参数的值限制在 Range.End - 1 范围内,并且不会生成任何错误。如果你执行 ARange.SetRange AEnd+100, AEnd+100,它仍然会将你的范围设置为 (AEnd-1, AEnd-1) - 并且会隐藏你实际上指向了一个无效位置的事实。另一方面,Document.Range 会抛出一个错误。 - dnep
啊哈,发现得不错。你能否澄清一下,“The Document.Range on the other hand” 到底是什么意思?也就是说,你所提到的错误会由哪段代码引起? - MartynA
我指的是我在答案中使用的Document.Range(start, end)方法/属性。抱歉。 - dnep
1
设置 ARange = Document.Range(AEnd, AEnd) 将会抛出一个错误。 - dnep
非常感谢您关于Document.Range()的解释。这解释了我在MS Word教材中发现的一些非常令人困惑的内容,即Document.Range可以带参数调用,但书中并没有说明如何使用或其目的是什么,这与我的预期不同。 - MartynA

0
以下是我在Word 15(Office 365)中使用Word 2010类型库成功实现的(我使用早期绑定,但晚期绑定也应该一样)。Word是一个TWordApplication,而aRange是一个WordRange
Word.Selection.EndKey(wdStory, wdMove);
aRange := Word.Selection.Range;
aRange.Text := 'This is new text added at the end.';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接