Suppose I want to add some text at the end of a document and immediately access
it as a Range object so I can set some properties of it without affecting the preceding text. Ideally, the Range.InsertAfter
method would return a Range object which would be perfect for this, but it doesn't.
It irks me that Word must know perfectly well what range defines the result of calling InsertAfter, but on the face of it, I need to calculate it "after the fact" from the length of the inserted text, or in some other way.
So I've devised a simple-minded work-around. In pseudo-code (actually it's Delphi
code but I hope that won't discourage VBA answers) what I do is this
ARange := Document.Range
ARange.Text := 'AAA'
AEnd := ARange.End - 1 // AEnd is an integer
ARange.SetRange(AEnd, AEnd)
ARange.Text := 'XXX'
ARange.Bold := True
and it seems that I can carry on indefinitely adding blocks of text to the end
of a document by repeating the second block of code.
The line
ARange.SetRange(AEnd, AEnd)
as I understand it, seems to construct a new Range at the end of the existing one (unlike calling Collapse on an existing range),
and works fine for the simple test cases I've tried. But it leaves me wondering
whether I'm missing a trick somewhere. Is there a more direct way to append a range
to a document and get a reference to it?
PS: I should have been a bit clearer that I'm trying to do this without using the Selection object (for a variety of reasons, including the fact that you can only have one of them at at time).
There are various ways to get the Range at the end of the document. You've discovered one, but as you say, it's somewhat circuitous. My preference:
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";
Collapsing the Range is conceptually like pressing the Right (or Left) arrow key when you have a selection. So rngEndOfDoc becomes a "point" rather than containing the entire content of the main body of the document.
FWIW I can never think of a situation when I'd use EndKey for this (emulate user actions) and I'd only change the Selection when I want to leave the user at the end of the document so that he can start typing at that location.
With thanks for the three admirable answers from others, I thought I would add my
own. The following are two versions of the function that I started out wishing Word provided
natively, returning an appended range.
The first version uses the MS Word objects in the MS Word Type Library import
unit that traditionally comes with Delphi (e.g. the Word2000.Pas one), and uses "early binding" automation,
while the second version does the same thing using late binding.
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;
Usage is e.g.
AppendedRange := AppendRange(ExistingRange);
AppendedRange.Text := 'YYY';
Think of the Document.Range as the union of all the possible ranges in the main document (i.e. apart from headings, footers, floating stuff etc.). It always starts before the first character and ends after the last character (that, in my experience, is always a hidden paragraph mark). It is not possible to define another range that is after the current Document.Range or, conceptually "append" anything after Document.Range, because there is no "after" the Document.Range (it always reaches to the end).
Thus, to extend a document with new text or other inline objects, you have to insert them at the end of the Document.Range - actually just before the end, as that last, hidden, paragraph mark must still be the final character of the document. This is just what you are doing in your pseudocode.
In VBA, an empty range at the end of the document can be referenced with
Document.Range(Document.Range.End-1, Document.Range.End-1)
Attempting to define it at Document.Range.End actually raises an error, as it points to after that last (hidden) character - and that is out of the Document - that is why we need the "-1".
After getting this range we may fill it with stuff - expanding it and, logically, the Document.Range. For example, to add text at the end of the active document, one would write
ActiveDocument.Range(ActiveDocument.Range.End-1, ActiveDocument.Range.End-1).Text = "New Text"
Notice that the same "final" empty range can be reached with:
Document.Bookmarks("\EndOfDoc").Range
The following works for me in Word 15 (Office 365) using the Word 2010 type library (I'm using early binding, but it should work the same with late binding as well). Word is a TWordApplication, and aRange is a WordRange.
Word.Selection.EndKey(wdStory, wdMove);
aRange := Word.Selection.Range;
aRange.Text := 'This is new text added at the end.';
I am new in VBA for Word
I was wondering if it is possible to use ASCII code in .MoveEndUntil for example: .MoveEndUntil cset:=Chr(13) & "-", Count:=wdForward
Yes, it is totally possible to use sample code from your question. However, it depends what you are trying to achieve. Your code will move the end of the selection until any of the specified characters are found in the document (see the documentation of the Range.MoveEndUntil method).
That means that moving the end of the range will stop as soon as a dash or a carriage return is reached.
However, this is probably not what you want. It looks like you are trying to extend the range until the next list item? If this should be the case then you can't use a simple Range.MoveEndUntil. You would have to expand the range to the end of the current paragraph and check whether the following paragraph has a list formatting.
I'm trying to do something with a multiple selection. I wanna add some text before every selected paragraph but, when I select multiple discontinuous paragraphs, if I do Selection.Paragraphs.Count I always get "1".
How could I work with all paragraphs apart?
Example:
Paragraph1(Selected first)
Paragraph2
Paragraph3(Selected second)
What I got when I try to add some text at the beginning of these paragraphs:
Paragraph1
Paragraph2
TEXTParagraph3
What I really want to obtain:
TEXTParagraph1
Paragraph2
TEXTParagraph3
I'm working like this:
sub x()
dim p as paragraph
for each p in selection.paragraphs
p.range.insertbefore("TEXT")
next
End sub
Word simply cannot do what you'd like for it to do. Developers have wished for this since multiple selections were introduced in 2003 (I think it was, might have been version 2007). Word's object model simply does not support it.
If this is something you want to provide to the user to make life easier you'll need to give the tool a way to mark the paragraphs so your code can recognize them. You could provide a macro, for example, that assigns an incrementing bookmark name to each selection (the user selects, then runs your macro; repeat for each paragraph). Your code can then address each bookmark and perform the actions. To make this more user friendly you can assign the macro to a keyboard shortcut and/or a button in the Ribbon/QAT and/or the right-click menu.
I am looking a way to convert the Bullets in Word document to simple text. E.g.
I have these kind of Bullets:
a)-> Apple
b)-> Orange
c)-> Mangoes
I want them to be like this:
a)Apple
b)Oranges
c)Mangoes
I am using this code but it removes the Bullets entirely:
Dim oPara As Paragraph
For Each oPara In ActiveDocument.Paragraphs()
Set r = oPara.Range
If r.ListFormat.RemoveNumbers = wdListBullet Then
r.ListFormat.ApplyListTemplate _
ListTemplate:=ListGalleries(wdNumberGallery) _
.ListTemplates(1)
End If
Set r = Nothing
Next
Is ActiveDocument.ConvertNumbersToText what you're after?
It can also be run on a specific list if you're not doing this globally.
ETA: It seems like ConvertNumbersToText takes a NumberType argument (this isn't documented by the 2010 spec that F1 brings up, but it is valid). Perhaps the default doesn't apply to all the bullets in your document. A combination of the three possibilities might work.
ActiveDocument.ConvertNumbersToText(wdNumberParagraph) 'Preset numbers you can add to paragraphs by selecting a template in the Bullets and Numbering dialog box.
ActiveDocument.ConvertNumbersToText(wdNumberListNum) 'Default value for LISTNUM fields.
ActiveDocument.ConvertNumbersToText(wdNumberAllNumbers) 'Default value for all other cases.
I tend to use the first one, but your case might be different.
the webapp was already done on office2007 and i need to convert it so it'll work in office2010.
i was able to convert the header generator part of the code but i have problem with the body of the doc itself. the code copy the data from a "data" doc and paste it into the generated doc.
appword.activewindow.activepane.view.seekview = 0
'set appsel1 = appword.activewindow.selection
set appsel1 = appword.window(filepath).selection -that is the original one
appdoc1.bookmarks("b1").select
appword.selection.insertafter("some text")
appsel1.endkey(6) -the code stops here
appword.selection.insertafter("some other text")
the iexplorer debuger says ERROR:appsel1 object required. and when i view its data using the iexplorer debugger its data is "empty" instead of "{...}"
can anyone tell me what i'm doing wrong
if you need more of the code tell me.
From MSDN
After this method is applied, the selection expands to include the new
text.
If you use this method with a selection that refers to an entire
paragraph, the text is inserted after the ending paragraph mark (the
text will appear at the beginning of the next paragraph). To insert
text at the end of a paragraph, determine the ending point and
subtract 1 from this location (the paragraph mark is one character).
However, if the selection ends with a paragraph mark that also happens
to be the end of the document, Microsoft Word inserts the text before
the final paragraph mark rather than creating a new paragraph at the
end of the document.
Also, if the selection is a bookmark, Word inserts the specified
text but does not extend the selection or the bookmark to include the
new text.
So I suspect that you still have no selected text.
I wonder if you can do a Selection Collapse(wdCollapseStart) but that's just a thought.