MS Office Forum / Word / Programming / November 2007
Identify page on which a bookmark is located
|
|
Thread rating:  |
BruceM - 23 Oct 2007 15:56 GMT I have code (obtained from this group in response to an earlier question) to print only the part of a document between two bookmarks. The following works inconsistently. Details are after the code. The code itself is in an Add-In.
Dim x1 As Long ' start character of bookmark Dim x2 As Long ' end character of bookmark Dim p1 As Long ' start page Dim p2 As Long ' end page
Dim rTmp As Range Set rTmp = ActiveDocument.Range ' Allow for a bookmark at the beginning of document If rTmp.Bookmarks("DocStart").Range.Start = 0 Then x1 = 1 Else x1 = rTmp.Bookmarks("DocStart").Range.Start End If x2 = rTmp.Bookmarks("DocEnd").Range.End p1 = rTmp.Characters(x1).Information(wdActiveEndPageNumber) p2 = rTmp.Characters(x2).Information(wdActiveEndPageNumber)
ActiveDocument.PrintOut _ Range:=wdPrintFromTo, From:=CStr(p1), To:=CStr(p2)
Set rTmp = Nothing
When the bookmarks DocStart and DocEnd are on the same page (so that only one page is printed, which is the case most of the time) it seems to work as intended. However, in other situations the results are mixed at best. For instance, DocStart is on page 7, but p1 is 9 when I step through the code. In the same document, if DocEnd is on page 8, it is identified as 11. That is, the variables p1 and p2 are 9 and 11 rather than 7 and 8. Another problem I have noted is that I cannot find a place for the DocEnd bookmark in a two-page document (I want to print both pages) that is not identifed as either page 1 or page 3. However, if I use the Word Count toolbar to count the number of characters, and replace x2 with that number (e.g. 2408), this line properly identifies p2 as 2: p2 = rTmp.Characters(x2).Information(wdActiveEndPageNumber)
If I do not manually set x2 to 2408, it is identified as something like 4500 (which is more than the total number of characters in the document), and that line of code throws the following error: 5941 - The expected member of the collection does not exist
That is all the information I have been able to obtain. The problem seems to be the same whenever it occurs: the character position of the bookmarks (the variables x1 and x2) are not identified properly.
If I could identify the page on which each of the bookmarks is located, I could get the code to do what is needed. If this is not possible, I could settle for setting the variables p1 and p2 manually for documents in which problems occur, and have the code above start by testing whether the variables already have a value, and using that value instead of the values generated by the code, or something like that. I would rather not do that, but I can accept a workaround if necessary.
I am using Word 2003. If it matters, the code above is designed to include the header and footer in the printout. Other code with which I experimented did not print the header and footer. It is better by far if I can include the header and footer.
Russ - 24 Oct 2007 06:56 GMT Bruce, Three things may trip you up: 1.Word usually determines page count from the current default printer driver. 2.Each section between section breaks may have different Page Setup formatting. So you may also have to include the section numbers that your starting bookmark and ending bookmark are in. 3.Shown Hidden text (Index fields, etc.) may alter what .Information... may see versus what Print Preview sees, if the option to not print hidden text is on. If that is the case, then use the not show hidden text toggle before using .Information...
Dim blnShowAll As Boolean blnShowAll = ActiveWindow.ActivePane.View.ShowAll ActiveWindow.ActivePane.View.ShowAll = False ...most of your code ActiveWindow.ActivePane.View.ShowAll = blnShowAll
> I have code (obtained from this group in response to an earlier question) to > print only the part of a document between two bookmarks. The following [quoted text clipped - 57 lines] > did not print the header and footer. It is better by far if I can include > the header and footer.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
BruceM - 24 Oct 2007 14:34 GMT Thanks for the reply. As it happens the ShowAll did not accomplish what was needed (it still gave an incorrect number for the character position of the second bookmark. However, as I investigated further I think I came up with something. So far it seems to work in all situations.
Dim p1 As Long ' start page Dim p2 As Long ' end page Dim AllChar As Long ' Section character count
Dim rTmp As Range Dim intSect As Integer
' Go to the first bookmark Selection.GoTo What:=wdGoToBookmark, Name:="DocStart"
' Find the number of the section containing the bookmark intSect = Selection.Information(wdActiveEndSectionNumber) ' Count the characters in the section AllChar = ActiveDocument.Sections(intSect).Range.ComputeStatistics(wdStatisticCharactersWithSpaces) Set rTmp = ActiveDocument.Sections(intSect).Range ' At the first character in the section, find the page number p1 = rTmp.Characters(1).Information(wdActiveEndPageNumber) ' At the last character in the section, find the page number p2 = rTmp.Characters(AllChar).Information(wdActiveEndPageNumber)
ActiveDocument.PrintOut _ Range:=wdPrintFromTo, From:=CStr(p1), To:=CStr(p2)
Set rTmp = Nothing
This assumes the printout is all of one section. I expect the code could be adapted for printing multiple (including non-contiguous) sections. I think I can avoid those situations, but if not, I think there is a way to work with it.
> Bruce, > Three things may trip you up: [quoted text clipped - 94 lines] >> include >> the header and footer. BruceM - 24 Oct 2007 21:05 GMT It seems I spoke too soon. In some situations the last page is not identified correctly. I tried adding your code (ShowAll), but it had no effect. I tried inserting another bookmark and finding the page as I did with the starting bookmark, but no good. It is as if the second page doesn't exist. To test, I deleted everything except for the 2-page section I intended to print. The character count that I got by using the Word Count toolbar was the same as the one I got for AllChar using the code, but p2 in the code was still 1, even though the last character was clearly on the second page. The strange part is that it usually works properly, but then on a very similar document it doesn't work. When it doesn't work, there is nothing to suggest why the two similar documents behave differently. I have found that if I add characters to the second page I can eventually get Word to understand that the end of the section is on the second page. Maybe I will need to add a few hundred spaces or something when I run into a problem, but I like to think there is something more elegant than that.
> Thanks for the reply. As it happens the ShowAll did not accomplish what > was needed (it still gave an incorrect number for the character position [quoted text clipped - 134 lines] >>> include >>> the header and footer. Russ - 25 Oct 2007 19:21 GMT Bruce, Some quick observations. I would use wdActiveEndAdjustedPageNumber For getting the end of the ranges. That automatically adjust page numbers to any page number manipulation going on in the document. ------------------------------------ I'm not seeing why you are involving characters?
Basically the pseudocode is: Set a new docstart2 range = to docstart.start, if docstart is not an insertion point and you don't want to collapse it to its start. Set a new docend2 range = to docend.end, if docsend is not an insertion point and you don't want to collapse it to its end.
Find wdActiveEndAdjustedPageNumber of those insertion points. (Optional, find wdActiveEndSectionNumber of those insertion points.)
Use that information in your printout command line.
> It seems I spoke too soon. In some situations the last page is not > identified correctly. I tried adding your code (ShowAll), but it had no [quoted text clipped - 152 lines] >>>> include >>>> the header and footer.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
BruceM - 25 Oct 2007 21:02 GMT I have not had a chance to try out your suggestions, and I am about to leave for the day, but I want to thank you for replying. I will try implementing your suggestions tomorrow. BTW, I used characters because I was blundering around and stumbled upon that, and it seemed to work. Actually, there is only one document so far where it fails, but I wouldn't be surprised if there are others. Clearly it is not all that reliable.
> Bruce, > Some quick observations. [quoted text clipped - 188 lines] >>>>> include >>>>> the header and footer. BruceM - 26 Oct 2007 15:35 GMT Thanks again for hanging in there on this issue. After posting (but before receiving your reply) I tried wdActiveEndAdjustedPageNumber, but it did not change the outcome on that one document that was giving me trouble. However, as I become more familiar with the options I found something else that seems to work:
Dim p1 As Long ' Start page Dim p2 As Long ' End page
Selection.GoTo what:=wdGoToBookmark, Name:="DocEnd" p2 = Selection.Information(wdActiveEndAdjustedPageNumber) Selection.GoTo what:=wdGoToBookmark, Name:="DocStart" p1 = Selection.Information(wdActiveEndAdjustedPageNumber)
ActiveDocument.PrintOut _ Range:=wdPrintFromTo, From:=CStr(p1), To:=CStr(p2)
Set rTmp = Nothing
I don't understand what you mean by "insertion point" in this context. Also, in my research I came across references to "collapsing". Because of my lack of understanding I do not have a view one way or the other about whether I "want to collapse it to its start". Another thing is that I could not figure out how to use the Start property. In my attempts to use it I got a type mismatch compile error. VBA Help documentation is spotty at best, so I can't figure out how to resolve that (or for that matter just how to use Start in the first place).
Any further insights (or links to explanations) would be appreciated, but in particular does it seem that the code above will address the problem? Again, I may want to print just page 1, or page 1 and 2, or page 7, or other combinations.
> Bruce, > Some quick observations. [quoted text clipped - 188 lines] >>>>> include >>>>> the header and footer. Russ - 30 Oct 2007 06:37 GMT Bruce says:
>I don't understand what you mean by "insertion point" in this context. The insertion point is the thin-blinking cursor position mark where you are typing text. Selection can be a selected word of text, a selected paragraph of text, etc.; or it can be no text selected but only the current cursor position or insertion point. I avoid using the term highlighted¹ for selected text, because Word provides highlight colors to truly highlight text, like a highlighter marker on paper. Selected text is text with temporarily reversed colors for font and background to make it obvious to the user what is selected and can be manipulated.
>Also, in my research I came cross references to ³collapsing². Because of my lack of understanding I do not have a view one way or the other about whether I ³want to collapse it to its start².
Here is what VBA Help says about the Collapse method: =======Quote Collapses a range or selection to the starting or ending position. After a range or selection is collapsed, the starting and ending points are equal. Syntax expression.Collapse(Direction) expression Required. An expression that returns a Range or Selection object. Direction Optional Variant. The direction in which to collapse the range or selection. Can be either of the following WdCollapseDirection constants: wdCollapseEnd or wdCollapseStart. The default value is wdCollapseStart. Remarks If you use wdCollapseEnd to collapse a range that refers to an entire paragraph, the range is located after the ending paragraph mark (the beginning of the next paragraph). However, you can move the range back one character by using the MoveEnd method after the range is collapsed, as shown in the following example. Set myRange = ActiveDocument.Paragraphs(1).Range myRange.Collapse Direction:=wdCollapseEnd myRange.MoveEnd Unit:=wdCharacter, Count:=-1 ======UnQuote Collapsing may only matter if your bookmarks are not just insertion points. If they include text, then it depends on whether you want to include the Start and End bookmarks ³full text² in the range of pages to print? Collapsing the current selection changes the current selection to an insertion point, either at the beginning or end or the previously selected text. So in order not to include both bookmarks text, you would collapse the Start-bookmark to its end (then find the adjusted page number) and the End-bookmark collapsed to its start (then find the adjusted page number).
>Another thing is that I could not figure out how to use the Start property. In my attempts to use it I got a type mismatch compile error. VBA Help documentation is spotty at best, so I can't figure out how to resolve that (or for that matter just how to use Start in the first place). Here¹s one thing it says about the .Start property: =======Quote Returns or sets the starting character position of a selection, range, or bookmark. Read/write Long. =======UnQuote Notice it says you can read or write to it, but then it says Long, which means it is of a type number. The .Start and .End properties return a number indicating how many characters from the document beginning, which is at .Start = 0 and .End = 0 or ActiveDocument.Range(0,0). Here¹s one thing it says about the .Information property: =======Quote Returns information about the specified selection or range. Read-only Variant. =======UnQuote Notice it is read only and returns information about a type selection or a type range input. (not a type number input, as what is returned by the .Start property; hence your type mismatch error.) What this boils down to is, by collapsing a range or selection to the start or end it still remains a selection type or range type and can be used as input to the .Information property. However you may not need to collapse to the end because, by default, the Selection.Information(wdActiveEndAdjustedPageNumber) returns the page number on which the *ActiveEnd* of the selection ends. Why use adjusted page argument - wdActiveEndAdjustedPageNumber? Because, for instance, if the document is divided into different Word sections with section breaks, each section can do its numbering differently, i.e. starting the page numbers counting from the number one again. And if your bookmarks span across different sections and you gathered the adjusted page number and the section information with wdActiveEndSectionNumber, you could ,for example, build up and use the string ³p2s2-p3s5² within the .PrintOut method as shown below in the quoted Word help to print a range of pages from Page 2(Section 2) to Page 3(Section 5). From regular Word Help: =========Quote Print specific pages and sections You can print specific pages, one or more sections, or a range of pages in more than one section. On the File menu, click Print. To print In the Pages box Noncontiguous pages Type the page numbers with commas between them. Type the range of pages with a hyphen between the starting and ending numbers in the range. For example, to print pages 2, 4, 5, 6, and 8, type 2,4-6,8 A range of pages within a section Type p page number s section number. For example, to print pages 5 through 7 in section 3, type p5s3-p7s3 An entire section Type s section number. For example, type s3 Noncontiguous sections Type the section numbers with commas between them. For example, type s3,s5 A range of pages across sections Type a range of page numbers and the sections that contain them with a hyphen between the starting and ending numbers in the range. For example, type p2s2-p3s5 =========UnQuote To see if you needed to build up a more ³complex² print page string, you would use ³if statements² to test if the bookmarks were in different sections. Choice between using Range or Selection? Nowadays, the preferred method is to use Ranges for speed since Selection requires Word to graphically indicate where the current selection is located and move it, if it changes. Logically, the Range speed should have worked that way from the beginning. It appeared that Word 97 had a bug in it that made Ranges slower than Selection, but it was changed in the next version of Word to make Ranges as speedy as they should have been. Selection still seems to work faster in Tables than Ranges at this time. Someone suggested it was because of the way Table structures are arranged in memory. Almost everything that can be defined by Selection can be defined by Range. When you record a macro, the code usually shows Selection because manually you must select objects to indicate what you want to apply actions upon. But most of the time you can trim the resultant, recorded code of the unnecessary options and change the Selections to Ranges for speed. In your code, in order to use Ranges and not have to use the Goto Bookmark, which Selects the Bookmark text, maybe requiring you to Collapse the Selection; you could use Ranges like this to find out which page the Previous Character to the First Character of the bookmark named 'End' Range is located or the Next Character after the Last Character of the bookmark named 'Start' Range is located: ActiveDocument.Bookmarks("End").Range.Characters.First.Previous.Information (wdActiveEndAdjustedPageNumber) ActiveDocument.Bookmarks("Start").Range.Characters.Last.Next.Information (wdActiveEndAdjustedPageNumber) or ActiveDocument.Bookmarks("Start").Range.Information (wdActiveEndAdjustedPageNumber) Since, by default, .Information (wdActiveEndAdjustedPageNumber) gives you where the end of the range or selection is located.
>> Thanks again for hanging in there on this issue. After posting (but before >> receiving your reply) I tried wdActiveEndAdjustedPageNumber, but it did not [quoted text clipped - 91 lines] >>>>> ' Count the characters in the section >>>>> AllChar = ActiveDocument.Sections(intSect).Range.ComputeStatistics(wdStatisticCharac>>>>> t
>>>>> er >>>>> sWithSpaces) [quoted text clipped - 125 lines] >>>>>>> include >>>>>>> the header and footer.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
BruceM - 30 Oct 2007 14:30 GMT Wow! Thanks for all of the information. I think I understand now that I may have to proceed differently if the bookmark text rather than a point in the document. I know what an insertion point is in Word, but it seems I over-thought it in a VBA context.
For some reason my Help file contains none of the information about methods and properties you have quoted, at least not by searching for the specific information (that is, "Collapse" produces nothing in VBA Help). Maybe I need to install SP3. For some reason that was not included with my automatic updates. Or maybe the information appears under another heading. My general experience with Help is that the information is often there, but it is so poorly indexed it may as well not be.
Thanks too for clearing up Sections and Ranges, and for pointing out the way to build a print string consisting of non-contiguous pages, just as that can be done with the Print dialog. I hope I don't need to do that for this project, but it is good to know I can.
I substituted your code: ActiveDocument.Bookmarks("End").Range.Characters.First. _ Previous.Information(wdActiveEndAdjustedPageNumber) ActiveDocument.Bookmarks("Start").Range _ .Information (wdActiveEndAdjustedPageNumber)
for my GoTo Bookmark code. Since the bookmarks were insertion points, as I understand it there was no need to collapse anything, so I think my system was OK, but this is more compact, which is my choice when all else is equal. Your explanation of how the page number is determined is very helpful, as is your explanation for the Type Mismatch error. I have saved this thread to my personal Help files.
Thanks again for all of your help and explanation. As I mentioned, I don't know why I don't have the information in VBA help, but the fact is I cannot find it, so your quoted information has been quite valuable.
> Bruce says: >>I don't understand what you mean by "insertion point" in this context. [quoted text clipped - 447 lines] >>>>>>>> include >>>>>>>> the header and footer. Russ - 31 Oct 2007 07:27 GMT Bruce, Glad to help. I learn as I read and participate in these forums.
Some useful keystroke shortcuts are: ALT/F11 to toggle between document and VBA Editor F1 for VBA contextual Help when the cursor is in a word in the VBA Editor code.
No Help files installed? Try Google: http://www.google.com/search?q=%22word%202003%22+install+VBA+help+file
> Wow! Thanks for all of the information. I think I understand now that I > may have to proceed differently if the bookmark text rather than a point in [quoted text clipped - 483 lines] >>>>>>>>> include >>>>>>>>> the header and footer.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
BruceM - 31 Oct 2007 12:17 GMT I knew about that Alt + F11 from Access, but I keep forgetting about F1. Just now I took another route into Help (via drilling down through Microsoft Word Visual Basic Reference). I found Properties, selected "I", and clicked "Information Property", only to be told the Help feature is not installed. I installed it, and now I seem to have the complete library. However, I was able to find some information in Help before installing the feature. Maybe the fragmentary information was in Office VB Reference, or maybe VB Documentation, but in any case it is pretty bewildering that I can search for a topic and be told there is no information on the topic rather than that Help is not installed. Then again, that is a lot to expect from Microsoft. BTW, the code has identified correctly the start and end pages of the print range in every document so far. Thanks again.
> Bruce, > Glad to help. I learn as I read and participate in these forums. [quoted text clipped - 558 lines] >>>>>>>>>> include >>>>>>>>>> the header and footer. Russ - 31 Oct 2007 19:23 GMT Bruce, Sounds like you have the VBA Help sorted out.
Regarding code: My only concern, as I think more about it, is that I didn't test it for bookmarks at the very beginning or end of a document, since it looking for a previous character or next character and there are none at the beginning and end respectively. You could drop the .previous or .next. And even the Characters.first and Characters.last if used, if your delimiting bookmarks will always be insertion points.
> I knew about that Alt + F11 from Access, but I keep forgetting about F1. > Just now I took another route into Help (via drilling down through Microsoft [quoted text clipped - 572 lines] >>>>>>>>>>> include >>>>>>>>>>> the header and footer.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
BruceM - 31 Oct 2007 20:34 GMT Thanks for the additional observations. The DocEnd bookmark will not be at the very end of the document for reasons having to do with the structure of the documents. Even if it is I don't think it will matter, since Previous rather than Next is being used there. The DocStart bookmark is identified by the code variation you suggested, so neither Previous or Next apply.
p1 = ActiveDocument.Bookmarks("DocStart").Range.Information(wdActiveEndAdjustedPageNumber) p2 = ActiveDocument.Bookmarks("DocEnd").Range.Characters _ .First.Previous.Information(wdActiveEndAdjustedPageNumber)
If I am reading this correctly, the bookmark DocStart is the Range used for p1, so wdActiveEndAdjustedPageNumber will find the page number at the end of the range. The bookmarks are intended to be insertion points, but even if they are not I don't see the end of the bookmark being on a different page from the beginning of the bookmark. As I understand, p2 is derived by going to the range represented by the DocEnd bookmark, going to the character before the first character in the range, and finding the page number there. Again, I see no problem with that as long as DocEnd is not at the very beginning of the document or of a page that is meant to be included in the print range. DocEnd is intended to be an insertion point, but even if it is not I expect Previous can be eliminated. Of course, all of this is based on the assumption that I understand what is going on with the code.
> Bruce, > Sounds like you have the VBA Help sorted out. [quoted text clipped - 647 lines] >>>>>>>>>>>> include >>>>>>>>>>>> the header and footer. Russ - 01 Nov 2007 06:20 GMT Bruce, It does seem, by what you wrote, that you do understand correctly what the code is doing.
> Thanks for the additional observations. The DocEnd bookmark will not be at > the very end of the document for reasons having to do with the structure of [quoted text clipped - 676 lines] >>>>>>>>>>>> include >>>>>>>>>>>> the header and footer.
 Signature Russ
drsmN0SPAMikleAThotmailD0Tcom.INVALID
|
|
|