也許你要用Word寫(xiě)一本24頁(yè)的宣傳冊(cè),但最后數(shù)來(lái)數(shù)去只有21頁(yè)。當(dāng)然,你不能讓最后3頁(yè)全部空白,而是應(yīng)該適當(dāng)調(diào)整文字,使它剛好有24頁(yè)。
這些問(wèn)題你經(jīng)常會(huì)遇到。本文的目標(biāo)就是設(shè)計(jì)一個(gè)插件,實(shí)現(xiàn)Word自動(dòng)擴(kuò)展和收縮文檔,使文檔符合指定的打印頁(yè)數(shù)。以前人們常用的WordPerfect軟件有這個(gè)功能,但Word卻從來(lái)沒(méi)有完全實(shí)現(xiàn)這個(gè)功能。之所以說(shuō)“沒(méi)有完全實(shí)現(xiàn)”,是因?yàn)閃ord也有一個(gè)簡(jiǎn)單的“減少一頁(yè)”功能,可以在打印預(yù)覽工具條上找到,如圖一所示,但Word的這個(gè)功能無(wú)法與WordPerfect的相比。
圖一:打印預(yù)覽工具欄
點(diǎn)擊“減少一頁(yè)”按鈕,Word會(huì)嘗試減小文檔中每種字體的大小。它的主要作用是避免將少量?jī)?nèi)容單獨(dú)放入一頁(yè)。按照微軟的建議,這個(gè)操作最好只用于最后一頁(yè)包含少量?jī)?nèi)容的短文檔。如果第一次操作沒(méi)有達(dá)到預(yù)期的目標(biāo),你可以重復(fù)執(zhí)行“減少一頁(yè)”命令,但最后可能得到一個(gè)字體小得難以接受的文檔。
相比之下,WordPerfect的這個(gè)功能靈活得多。首先,它既可以收縮文檔,也可以擴(kuò)展文檔,只要目標(biāo)頁(yè)數(shù)和當(dāng)前頁(yè)數(shù)的差異不超過(guò)50%即可。第二,你可以選擇通過(guò)哪些途徑使文檔符合指定的頁(yè)數(shù)要求,除了改變字體之外,你還可以調(diào)整行距以及頁(yè)的上、下、左、右邊距。WordPerfect會(huì)根據(jù)用戶指定的選項(xiàng)分析當(dāng)前文檔,自動(dòng)修改文檔格式,使文檔符合指定的頁(yè)數(shù)要求。
圖二:自動(dòng)調(diào)整文檔頁(yè)數(shù)
本文的目標(biāo)是模仿WordPerfect,在Word中實(shí)現(xiàn)文檔頁(yè)數(shù)自動(dòng)調(diào)整功能。調(diào)整頁(yè)數(shù)的界面如圖二所示,用戶可以選擇調(diào)整哪些項(xiàng)目、調(diào)整的范圍,然后點(diǎn)擊“確定”按鈕開(kāi)始自動(dòng)調(diào)整。當(dāng)然,實(shí)現(xiàn)這種功能需要用到Word宏,也就是要用VBA編程。不過(guò)本文的代碼并不是特別復(fù)雜,只要了解一些基礎(chǔ)知識(shí),就很容易理解本文的代碼。本文的插件適用于Word 2000和XP,文章中凡是涉及菜單名字、對(duì)話框的地方,都以Word XP為標(biāo)準(zhǔn)。
一、調(diào)整文檔占用空間的基本手段
Word提供了七個(gè)改變字體大小和調(diào)整行距的內(nèi)建命令,所有這些命令都可以用等價(jià)的VBA代碼表示。在圖三中,我把這些命令和“減少一頁(yè)”集中到了一個(gè)自定義的工具欄上。
圖三:調(diào)整文檔占用空間的內(nèi)建命令
如果你也想得到這個(gè)工具欄,可按如下步驟設(shè)置:選擇菜單“工具->自定義”,選擇“工具欄”選項(xiàng)卡,新建一個(gè)工具欄,將它命名為“擴(kuò)展與縮減文檔頁(yè)數(shù)”,然后選擇“自定義”對(duì)話框的“命令”頁(yè),在“類別”列表中選擇“所有命令”,接著從“命令”列表把各個(gè)命令拖到新建的工具欄上就可以了。
1.1 調(diào)整字體
首先來(lái)看第一個(gè)命令“減少一頁(yè)”。在Word宏中,該命令對(duì)應(yīng)的VBA指令是ActiveDocument.FitToPages。需要注意的是,調(diào)用該指令的代碼必須有健全的錯(cuò)誤處理機(jī)制,因?yàn)槿绻?Word 無(wú)法將文檔的頁(yè)數(shù)減少一頁(yè),則該方法會(huì)導(dǎo)致出錯(cuò)。Word的幫助只提到了編號(hào)為5538的錯(cuò)誤“Word無(wú)法按一頁(yè)縮小文檔,因?yàn)榇宋臋n只有一頁(yè)”。但在實(shí)際應(yīng)用中,出現(xiàn)另一個(gè)編號(hào)為5539的錯(cuò)誤可能性更大。5539錯(cuò)誤的意思是“經(jīng)過(guò)數(shù)次嘗試,Word無(wú)法按一頁(yè)來(lái)縮小文檔”。據(jù)測(cè)試,只要文檔的字體被縮小到6磅,Word會(huì)提示這個(gè)錯(cuò)誤,也許Word認(rèn)為這是可以保證文檔清晰可讀的最小字體,所以不再繼續(xù)縮小字體。
“縮小字體”和“增大字體”兩個(gè)命令分別對(duì)應(yīng)Selection.Font.Shrink和Selection.Font.Grow,這兩個(gè)方法可用來(lái)調(diào)整選中區(qū)域的字體大小。Shrink方法把字體縮小一級(jí),如果用戶選中的內(nèi)容字體大小不一,則每種字體大小分別被縮減一級(jí)。Grow方法的作用恰好相反。“一級(jí)”這個(gè)概念的含義必須說(shuō)明一下。如果文字的當(dāng)前大小是20,則比它大一級(jí)不是21,而是22;比20小一級(jí)的不是19,而是18。也就是說(shuō),Word對(duì)文字大小級(jí)別的解釋與“格式”工具欄上列表框的值對(duì)應(yīng),如圖四所示。
圖四:Word的字體分級(jí)
仔細(xì)觀察圖四的列表,每一級(jí)之間的距離沒(méi)有任何規(guī)律,有的距離大,有的距離小。微軟沒(méi)有解釋這么安排的理由,但可以猜想,如果一段文字既有標(biāo)題也有正文,用Shrink和Grow方法調(diào)整大小時(shí),這種分級(jí)安排有利于維持某種平衡。
用FitToPages和Shrink方法縮減文檔頁(yè)數(shù)時(shí),應(yīng)注意兩者的工作方式有所不同。Shrink按照預(yù)定義的級(jí)別縮減字體大小,字體可以小到1磅。FitToPages不同,它按照0.5磅的精度精確調(diào)整字體大小,但不允許正文字體小于6磅。
VBA沒(méi)有提供直接與圖三“將字體縮小1磅”、“將字體增大1磅”對(duì)應(yīng)的命令。如果用記錄宏的辦法獲取這兩個(gè)按鈕對(duì)應(yīng)的代碼,可得到如下結(jié)果:
- 將字體縮小1磅:Selection.Font.Size = Selection.Font.Size - 1
- 將字體增加1磅:Selection.Font.Size = Selection.Font.Size + 1
如果選中一段包含多種字體大小的文字,然后點(diǎn)擊“將字體縮小1磅”按鈕,Word會(huì)自動(dòng)根據(jù)原有的字體大小,分別將它們減小1磅。但是,如果將這個(gè)操作記錄成宏,然后再重新執(zhí)行這個(gè)宏,Word會(huì)提示錯(cuò)誤“運(yùn)行時(shí)錯(cuò)誤4120,參數(shù)無(wú)效”。有興趣的讀者,可在VB調(diào)試器中分析代碼的運(yùn)行過(guò)程。對(duì)于“將字體增加1磅”按鈕,情況也完全一樣?梢(jiàn),對(duì)于這兩個(gè)命令,VBA不支持包含多種字體大小的情形!
怎么辦呢?我們知道,點(diǎn)擊“將字體縮小/增加1磅”按鈕不會(huì)因?yàn)榇嬖诙喾N字體大小而出現(xiàn)問(wèn)題。因此,只要我們模擬按鈕點(diǎn)擊動(dòng)作,就可以繞過(guò)Selection和Font對(duì)象。
每一個(gè)Office的CommandBar按鈕都有一個(gè)數(shù)值型的ID屬性,“將字體縮小1磅”按鈕的ID是310,“將字體增加1磅”按鈕的ID是311。只要有了按鈕的ID,就可以用CommandBars屬性的FindControl方法創(chuàng)建按鈕對(duì)象,然后利用Execute方法執(zhí)行與CommandBar關(guān)聯(lián)的操作。也就是說(shuō),用下面的代碼可以執(zhí)行“將字體縮小1磅”和“將字體增加1磅”命令:
- CommandBars.FindControl(ID:=310).Execute
- CommandBars.FindControl(ID:=311).Execute
1.2 調(diào)整行距
下面來(lái)看看如何模擬WordPerfect第二類調(diào)整文檔空間的方法,即調(diào)整行距。Word有三個(gè)內(nèi)建的命令來(lái)調(diào)整行距(各個(gè)行之間的垂直距離),如圖三最下方的三個(gè)按鈕所示,它們對(duì)應(yīng)的VBA代碼是:Selection.ParagraphFormat.Space1,Selection.ParagraphFormat.Space15,Selection.ParagraphFormat.Space2。
Space1方法為指定段落設(shè)置單倍行距,準(zhǔn)確的間距將取決于各行內(nèi)字符最大的字號(hào)。Space15方法為指定段落設(shè)置1.5倍行距,即各段內(nèi)字符的最大字號(hào)加上6磅;Space2方法設(shè)置2倍行距,即各段內(nèi)字符最大的字號(hào)加上12磅。
但是,利用這些方法來(lái)調(diào)整行間距不是最好的辦法,因?yàn)閷?duì)于需要精確的場(chǎng)合,它們實(shí)在顯得太粗糙了。使用“格式->段落”菜單可以更精確地控制行距,如圖五所示:
圖五:指定行距的六種規(guī)則
“段落”對(duì)話框允許按照六種不同的規(guī)則指定行距。如果指定了后面三種規(guī)則之一,還必須指定“設(shè)置值”。與此對(duì)應(yīng),在Word VBA中,行距是由兩個(gè)屬性控制的:LineSpacingRule和LineSpacing。Paragraph、ParagraphFormat、Paragraphs集合對(duì)象都提供了這些屬性。行距的規(guī)則通過(guò)LineSpacingRule屬性值設(shè)定,可以指定的常量值包括:wdLineSpaceSingle、wdLineSpace1pt5、wdLineSpaceDouble、wdLineSpaceAtLeast、wdLineSpaceExactly和wdLineSpaceMultiple。如果把規(guī)則設(shè)置成后面三個(gè)常量值之一,同時(shí)還必須設(shè)定LineSpacing屬性。LineSpacing屬性用來(lái)返回或設(shè)置指定段落或范圍的行距,單位是磅。要在文檔中擴(kuò)展或收縮文字,最好把LineSpacingRule屬性設(shè)置成wdLineSpaceMultiple。這樣,我們可以讓行距總是和段落中最大字體的大小有關(guān)。例如下面的代碼將當(dāng)前文檔所有段落的行距增加百分之三:
With ActiveDocument.Paragraphs
.LineSpacingRule = wdLineSpaceMultiple
.LineSpacing = LinesToPoints(1.03)
End With
這里用到了LinesToPoints方法。這個(gè)方法用來(lái)把度量單位從行轉(zhuǎn)換為磅(1行=12磅),返回值是Single類型。按照這種方法,行距值可以調(diào)整到相當(dāng)精確的程度。但應(yīng)當(dāng)注意的是,Word會(huì)以二十分之一磅為單位調(diào)整最終的行距。例如在上面的例子中,最終的行距不是12.36磅(1.03 X 12),而是12.35磅。
為了便于閱讀,最好不要將行距縮小到90-92%(約11磅)以下。如果小于這個(gè)值,行的高度可能不夠,某些文字的頂端或末端可能被切割。但是,如果要擴(kuò)展一個(gè)文檔,這種辦法是非常理想的,不僅效果顯著,而且永遠(yuǎn)不會(huì)影響文檔的可讀性。
1.3 頁(yè)邊距
WordPerfect允許修改頁(yè)四邊的空白距離,下面來(lái)看看如何在Word中作類似的調(diào)整。不過(guò)首先需要注意的是,無(wú)限制減小頁(yè)邊距不一定安全,因?yàn)榭赡芘c打印機(jī)支持的邊距范圍產(chǎn)生沖突。另外,如果文檔包含頁(yè)眉、裝訂線等,調(diào)整整個(gè)文檔的邊距之后可能會(huì)出現(xiàn)意外的結(jié)果。
在Word VBA中,與四種邊距對(duì)應(yīng)的TopMargin、BottomMargin、LeftMargin和RightMargin屬性屬于PageSetup對(duì)象,屬性的類型是Single,可用來(lái)設(shè)置或返回頁(yè)邊與文字邊緣的距離,單位是磅。如果你不習(xí)慣用磅作為計(jì)量單位,可以借助轉(zhuǎn)換函數(shù)使用自己熟悉的單位,例如英寸。例如,下面的例子中,InchesToPoints函數(shù)把1.5英寸轉(zhuǎn)轉(zhuǎn)成108磅(1英寸等于72磅):
With ActiveDocument.PageSetup .LeftMargin = InchesToPoints(1.5) .RightMargin = InchesToPoints(1.5) End With
PageSetup對(duì)象屬于Section對(duì)象。也就是說(shuō),如果一個(gè)文檔包含多個(gè)節(jié)(Section),就可以提取出多個(gè)PageSetup對(duì)象,每一個(gè)PageSetup對(duì)象可能有不同的邊距。所以,如果文檔包含多個(gè)節(jié)且各個(gè)節(jié)的左邊距不同,下面的代碼不能得到正確結(jié)果,它將返回wdUndefined值(9999999):
Debug.Print ActiveDocument.PageSetup.LeftMargin
如果要調(diào)整整個(gè)文檔的邊距,就必須分別處理各個(gè)節(jié)的邊距,如下面的例子所示。這段代碼首先獲取各個(gè)節(jié)的當(dāng)前左、右邊距,然后把它們縮小20%:
Dim ObjSection As SectionFor Each ObjSection In ActiveDocument.Sections With ObjSection.PageSetup .LeftMargin = .LeftMargin * 0.8 .RightMargin = .RightMargin * 0.8 End WithNext
二、實(shí)現(xiàn)自動(dòng)調(diào)整功能
前面分析了在VBA中調(diào)整文檔占用空間的各種途徑。利用這些技術(shù)可以編寫(xiě)出下面的DocSizer類,實(shí)現(xiàn)調(diào)整文檔頁(yè)數(shù)的核心功能。
DocSizer類主要提供了10個(gè)屬性和一個(gè)Execute方法。10個(gè)屬性的含義如表一所示。
表一 屬性 說(shuō)明 AdjustItems 可選,Long。指定可以通過(guò)哪些項(xiàng)目來(lái)調(diào)整文檔占用的空間。允許使用下列枚舉常量的任意組合:adjFontSize(1),adjLineSpacing(2),adjMarginLeft(4),adjMarginRight(8),adjMarginTop(16),andadjMarginBottom(32)。如果忽略,則默認(rèn)是adjAll常量(63),即前面6個(gè)選項(xiàng)的組合。 NumTargetPages 必需,Long,可讀寫(xiě)。指定目標(biāo)頁(yè)數(shù),與現(xiàn)有頁(yè)數(shù)的差距不能超過(guò)50%。
MinLeftMargin
MinRightMargin
MinTopMargin
MinBottomMargin
可選,Single。用來(lái)指定必須保留的最小邊距,可用來(lái)防止邊距縮小得太多以至于超出打印機(jī)允許的范圍。如果忽略,默認(rèn)保留的最小邊距是文檔第一節(jié)邊距的70%。 MinFontSize 可選,Single。指定“正文”樣式的字體最小可以調(diào)整到多少。如果忽略,則默認(rèn)最小允許的字體是6磅。 MinLineSpacing 可選,Single。指定“正文”樣式中的行距最小可以調(diào)整到多少。如果忽略,則默認(rèn)11磅(相當(dāng)于一行的92%)。如果行距小于11磅,字符可能被切割。 NumCurrentPages 只讀,Long。返回文檔初始的頁(yè)數(shù)。執(zhí)行Execute方法之后,返回值將是調(diào)整后的頁(yè)數(shù)。 UndoAfterFailure 可選,Boolean。如果設(shè)置成True,一旦調(diào)整之后未能達(dá)到預(yù)定的頁(yè)數(shù)要求,則撤銷所有對(duì)文檔格式的修改,恢復(fù)文檔的原始狀態(tài)。默認(rèn)值是True,如果要保留調(diào)整后的結(jié)果(即使頁(yè)數(shù)不能達(dá)到預(yù)定的要求),則應(yīng)當(dāng)顯式地把該屬性設(shè)置成False。
Execute方法啟動(dòng)調(diào)整文檔頁(yè)數(shù)的操作,如果能夠達(dá)到預(yù)期的頁(yè)數(shù)要求,返回True;否則返回False。另外,Execute方法還可能返回錯(cuò)誤,利用Err.Description可獲得錯(cuò)誤的描述信息。下面是DocSizer的主要代碼:
'公用變量,可讀寫(xiě)的屬性Public NumTargetPages As Long '目標(biāo)頁(yè)數(shù)Public UndoAfterFailure As Boolean '調(diào)整失敗后恢復(fù)'可調(diào)整的項(xiàng)目'包括:字體,行距,左、右、上、下邊距Public Enum adjItems adjFontSize = 1 adjLineSpacing = 2 adjMarginLeft = 4 adjMarginRight = 8 adjMarginTop = 16 adjMarginBottom = 32End Enum'全部項(xiàng)目都可以調(diào)整Const ADJ_ALL = adjFontSize Or adjLineSpacing Or adjMarginLeft Or _ adjMarginRight Or adjMarginTop Or adjMarginBottom'錯(cuò)誤信息'錯(cuò)誤信息常量聲明,略...Const ERR_MSG_OPERATION_SUCCESSFUL = "操作成功!該文檔現(xiàn)在包含預(yù)定的頁(yè)數(shù)。"Const ERR_MSG_SHRINK_FAILED = "錯(cuò)誤!無(wú)法把該文檔縮減到預(yù)定的頁(yè)數(shù)。"Const ERR_MSG_STRETCH_FAILED = "錯(cuò)誤!無(wú)法把該文檔擴(kuò)展到預(yù)定的頁(yè)數(shù)。"Const ERR_MSG_TARGETPAGES_OVERFLOW = "錯(cuò)誤!目標(biāo)頁(yè)數(shù)與現(xiàn)有頁(yè)數(shù)的差距不能超過(guò)50%。"Const ERR_MSG_TARGETPAGES_SAME_AS_CURRENT_PAGES = "錯(cuò)誤!目標(biāo)頁(yè)數(shù)與現(xiàn)有頁(yè)數(shù)完全一樣。"Const ERR_MSG_NO_TARGETPAGES = "錯(cuò)誤!沒(méi)有指定目標(biāo)頁(yè)數(shù)。"'默認(rèn)允許的最小字體Const MIN_FONTSIZE As Single = 6'默認(rèn)允許的最小行距Const MIN_LINESPACING As Single = 11'允許將頁(yè)邊距縮小到多少(百分比)Const MIN_MARGINS_PERCENTAGE As Single = 0.7Const DEF_MARGIN_ADJUSTMENT As Long = 12'聲明其他對(duì)象型變量,略...'======類的屬性和方法======='類初始化Private Sub Class_Initialize()If Documents.Count Then '用于撤銷已執(zhí)行的格式修改操作 Set objUndoList = CommandBars.FindControl(ID:=128)End If'默認(rèn)修改失敗后恢復(fù)UndoAfterFailure = TrueEnd SubPrivate Sub Class_Terminate()Set objUndoList = NothingEnd SubProperty Get CurPageCount() As Long'獲得文檔的當(dāng)前頁(yè)數(shù)If Documents.Count Then CurPageCount = ActiveDocument.ComputeStatistics(wdStatisticPages)End IfEnd PropertyPrivate Property Get sDefaultLineSpacing()'返回"正文"樣式的行距,磅With ActiveDocument.Styles(wdStyleNormal).ParagraphFormat '行距規(guī)則? Select Case .LineSpacingRule Case wdLineSpaceMultiple sDefaultLineSpacing = .LineSpacing Case wdLineSpaceSingle, wdLineSpace1pt5, wdLineSpaceDouble ' 0, 1,或 2 sDefaultLineSpacing = (.LineSpacingRule + 1) * 12 Case Else '忽略wdLineSpaceExactly和wdLineSpaceAtLeast sDefaultLineSpacing = 12 End SelectEnd WithEnd Property
Private Property Get DefaultFontRange() As Range
'找到一個(gè)按照"正文"樣式格式化的Range。
'縮小字體時(shí),查看該Range就可以知道字體縮小
'到了什么程度
If Documents.Count Then
With Selection
Set objOriginalSel = .Range
With .Find
.ClearFormatting
.Font.Size = ActiveDocument.Styles(wdStyleNormal).Font.Size
.Text = vbNullString
.Forward = True
.Wrap = wdFindContinue
.Format = True
If .Execute Then
Set DefaultFontRange = Selection.Range
Else
Set DefaultFontRange = Nothing
End If
End With
objOriginalSel.Select
End With
End If
End Property
Private Property Get nCurUndoItems()
'返回‘常用’工具欄‘撤消’列表的項(xiàng)目數(shù)
If IsObject(objUndoList) Then
With objUndoList
If .Enabled Then nCurUndoItems = .ListCount
End With
End If
End Property
Function Execute() As Boolean
'根據(jù)設(shè)定的參數(shù),將文檔頁(yè)數(shù)調(diào)整到預(yù)定的數(shù)量
On Error Resume Next
nInitialPages = CurPageCount '初始頁(yè)數(shù)
'‘撤消’列表的當(dāng)前項(xiàng)數(shù)
nInitialUndoItems = nCurUndoItems
'默認(rèn)允許以所有手段調(diào)整文字占用的空間
If nAdjustItems = 0 Then nAdjustItems = ADJ_ALL
'是否允許調(diào)整邊距
bAdjustAnyMargin = CBool(nAdjustItems And adjMarginLeft) Or _
CBool(nAdjustItems And adjMarginRight) Or _
CBool(nAdjustItems And adjMarginTop) Or _
CBool(nAdjustItems And adjMarginBottom)
'根據(jù)目標(biāo)頁(yè)數(shù)的不同,執(zhí)行不同的操作(縮減頁(yè)數(shù)或擴(kuò)展頁(yè)數(shù))
Select Case NumTargetPages
Case 0
'沒(méi)有指定目標(biāo)頁(yè)數(shù)
Err.Raise ERR_NO_TARGETPAGES, , ERR_MSG_NO_TARGETPAGES
Case Is > nInitialPages * 1.5, Is < (nInitialPages + 1) \ 2
'目標(biāo)頁(yè)數(shù)與現(xiàn)有頁(yè)數(shù)的差距不能超過(guò)50%
Err.Raise ERR_TARGETPAGES_OVERFLOW, , ERR_MSG_TARGETPAGES_OVERFLOW
Case Is < nInitialPages
'縮減頁(yè)數(shù)
ShrinkToFit
Execute = (CurPageCount = NumTargetPages)
If Execute = True Then
'縮減頁(yè)數(shù)成功
Err.Raise ERR_OPERATION_SUCCESSFUL, , ERR_MSG_OPERATION_SUCCESSFUL
Else
'縮減頁(yè)數(shù)失敗
Err.Raise ERR_SHRINK_FAILED, , ERR_MSG_SHRINK_FAILED
'是否恢復(fù)到調(diào)整頁(yè)數(shù)之前的原始文檔?
If UndoAfterFailure Then UndoAll
End If
Case Is > nInitialPages
'擴(kuò)展頁(yè)數(shù)
StretchToFit
Execute = (CurPageCount = NumTargetPages)
If Execute = True Then
'擴(kuò)展頁(yè)數(shù)成功
Err.Raise ERR_OPERATION_SUCCESSFUL, , ERR_MSG_OPERATION_SUCCESSFUL
Else
'擴(kuò)展頁(yè)數(shù)失敗
Err.Raise ERR_STRETCH_FAILED, , ERR_MSG_STRETCH_FAILED
'是否恢復(fù)到調(diào)整頁(yè)數(shù)之前的原始文檔?
If UndoAfterFailure Then UndoAll
End If
Case Else
End Select
If IsObjectValid(objOriginalSel) Then objOriginalSel.Select
'刷新屏幕
Application.ScreenRefresh
End Function
Private Sub StretchToFit()
'擴(kuò)展文檔頁(yè)數(shù)
With ActiveDocument
'如果允許調(diào)整字體...
If CBool(nAdjustItems And adjFontSize) Then
Do Until bFontDone
'增大字體
.Range.Font.Grow
'分析頁(yè)數(shù)
nCurPages = CurPageCount
'當(dāng)前頁(yè)數(shù)是否等于目標(biāo)頁(yè)數(shù)?
If nCurPages = NumTargetPages Then
' 已經(jīng)達(dá)到目標(biāo)頁(yè)數(shù)
Exit Sub
ElseIf nCurPages > NumTargetPages Then
'頁(yè)數(shù)太多了。必須撤消最后一次修改操作
.Undo 1
bFontDone = True
Else
'文檔頁(yè)數(shù)仍舊太少,繼續(xù)擴(kuò)展文檔
End If
Loop
End If
'調(diào)整行距,略...
'調(diào)整邊距,略...
End With
End Sub
Private Sub ShrinkToFit()
'縮減文檔頁(yè)數(shù)
With ActiveDocument
'如果允許調(diào)整字體...
If CBool(nAdjustItems And adjFontSize) Then
Dim sCurFontSize As Single
'確定最小字體
If sMinFontSize = 0 Then sMinFontSize = MIN_FONTSIZE
Dim rNormalFont As Range
Set rNormalFont = DefaultFontRange
Do Until bFontDone
' FitToPages執(zhí)行失敗會(huì)出現(xiàn)5538和5539錯(cuò)誤
On Error Resume Next
.FitToPages
Select Case Err
Case 5538, 5539
' FitToPages失敗,結(jié)束循環(huán)
Err.Clear
bFontDone = True
Case 0 'FitToPages執(zhí)行成功
'文檔是否包含用‘正文’樣式格式化的文字?
If IsObjectValid(rNormalFont) Then
'它當(dāng)前的字體大小是多少?
sCurFontSize = rNormalFont.Font.Size
'如果字體已經(jīng)達(dá)到允許的最小極限,則結(jié)束循環(huán)
If sCurFontSize < sMinFontSize Then
.Undo 1
bFontDone = True
End If
Else
'文檔不包含‘正文’樣式大小的文字。字體可能被調(diào)整到6
'磅(FitToPages的下限)
End If
Case Else '其他不能確定的異常
Err.Clear
bFontDone = True
End Select
'分析頁(yè)數(shù)
nCurPages = CurPageCount
'當(dāng)前頁(yè)數(shù)是否等于目標(biāo)頁(yè)數(shù)?
If nCurPages = NumTargetPages Then
'已經(jīng)達(dá)到目標(biāo)頁(yè)數(shù)
Exit Sub
ElseIf nCurPages < NumTargetPages Then
'頁(yè)數(shù)太少了。如果不允許調(diào)整行距,撤消最后的操作
If Not CBool(nAdjustItems And adjLineSpacing) Then
.Undo 1
End If
bFontDone = True
Else
'頁(yè)數(shù)仍舊太多,繼續(xù)縮減頁(yè)數(shù)
End If
Loop
End If
'調(diào)整行距,略...
'調(diào)整邊距,略...
End With
End Sub
Private Sub UndoAll()
'撤消所有調(diào)整頁(yè)數(shù)的操作,略...
End Sub可以看到,擴(kuò)展頁(yè)數(shù)的過(guò)程(StretchToFit)比較簡(jiǎn)單,縮減頁(yè)數(shù)的過(guò)程(ShrinkToFit)稍微復(fù)雜一點(diǎn)。代碼的主要思路是:每次調(diào)整字體大小、行距或邊距之后,檢查一下CurPageCount屬性,看看是否已經(jīng)達(dá)到目標(biāo)頁(yè)數(shù)。如果已經(jīng)達(dá)到,調(diào)整過(guò)程結(jié)束,Execute方法返回True;如果調(diào)整之后頁(yè)數(shù)變得太多(或太少),例如縮小字體之后頁(yè)數(shù)小于目標(biāo)頁(yè)數(shù),則撤消最后一次操作,嘗試另一種調(diào)整頁(yè)數(shù)的辦法。當(dāng)所有調(diào)整頁(yè)數(shù)的辦法都已經(jīng)試遍,而頁(yè)數(shù)仍未能達(dá)到要求,則Execute返回False。
建議至少用字體和行距兩種辦法調(diào)整文檔的頁(yè)數(shù),這樣可以大大增加調(diào)整成功的可能性。當(dāng)然,不能排除未能達(dá)到目標(biāo)頁(yè)數(shù)的情形出現(xiàn),導(dǎo)致這種情形的主要原因可能是文檔包含太多手工插入的分頁(yè)符、大型圖片,或者是因?yàn)槟繕?biāo)頁(yè)數(shù)和現(xiàn)有頁(yè)數(shù)的差距太大。
三、設(shè)計(jì)用戶界面
前面介紹了調(diào)整文檔頁(yè)數(shù)的核心思路和代碼。下面來(lái)看看制作用戶界面的過(guò)程。用戶界面主要包括兩部分:菜單和對(duì)話框。圖六是加入到“文件->打印預(yù)覽”前面的“調(diào)整頁(yè)數(shù)”菜單。
圖六:“調(diào)整頁(yè)數(shù)”菜單“調(diào)整頁(yè)數(shù)”菜單包括三個(gè)選項(xiàng)。第一個(gè)選項(xiàng)允許指定目標(biāo)頁(yè)數(shù),然后根據(jù)默認(rèn)的參數(shù)執(zhí)行調(diào)整操作。第二個(gè)選項(xiàng)等同于Word的“減少一頁(yè)”功能,但原來(lái)這個(gè)功能只能在打印預(yù)覽狀態(tài)下使用。第三個(gè)選項(xiàng)顯示出圖二的對(duì)話框,用戶自定義調(diào)整頁(yè)數(shù)的參數(shù),然后點(diǎn)擊“確定”按鈕開(kāi)始調(diào)整頁(yè)數(shù)。如果用戶試圖調(diào)整文檔頁(yè)數(shù)時(shí),文檔沒(méi)有保存,會(huì)出現(xiàn)圖七的提示。
圖七:調(diào)整頁(yè)數(shù)之前保存文檔設(shè)置菜單的代碼和其他代碼一起保存在一個(gè)插件模板DocSizer.dot之中。DocSizer.dot的主要內(nèi)容如圖八所示。其中:
- frmDocSizer窗體:包含圖二的對(duì)話框。
- Interface模塊:包括生成圖六菜單、根據(jù)默認(rèn)參數(shù)調(diào)整文檔頁(yè)數(shù)、顯示圖二對(duì)話框的代碼。
- Context類模塊:處理上下文信息。
- DocSizer類模塊:實(shí)現(xiàn)調(diào)整文檔頁(yè)數(shù)的核心功能。
圖八:DocSizer模板的主要內(nèi)容
DocSizer.dot必須放入Word的自動(dòng)啟動(dòng)目錄。對(duì)于Windows 2000/XP和Office 2000/XP,啟動(dòng)目錄通常是\Documents and Settings\<用戶名字>\Application Data\Microsoft\Word\STARTUP。Word會(huì)自動(dòng)加載該目錄下的模板,這樣我們就可以在Word啟動(dòng)時(shí)加入“調(diào)整頁(yè)數(shù)”菜單。
因篇幅關(guān)系,這里不再介紹Context類模塊和Interface模塊的代碼,但你可以參見(jiàn)本文的附件DocSizer.dot,代碼中包含了詳細(xì)的注釋。將DocSizer.dot安裝到Word的啟動(dòng)目錄下,啟動(dòng)Word就可以看到“文件->打印預(yù)覽”前面增加了一個(gè)“調(diào)整頁(yè)數(shù)”菜單。啟動(dòng)目錄的具體位置,可查看Word菜單“工具->選項(xiàng)”再選擇“文件位置”。如果你要查看DocSizer.dot的完整代碼,先按正常方式打開(kāi)它,然后選擇菜單“工具->宏->宏”,再選擇“編輯”即可。
作為一種通用軟件,Word無(wú)法照顧到每一個(gè)用戶的特殊要求和使用習(xí)慣。但是,Word提供了VBA編程支持和完善的對(duì)象模型。正如本文例子所顯示的,利用這些技術(shù),我們可以隨心所欲地定制Word,提高工作效率。
'調(diào)整行距,略...
'調(diào)整邊距,略...
End With
End Sub
Private Sub UndoAll()
'撤消所有調(diào)整頁(yè)數(shù)的操作,略...
End Sub
可以看到,擴(kuò)展頁(yè)數(shù)的過(guò)程(StretchToFit)比較簡(jiǎn)單,縮減頁(yè)數(shù)的過(guò)程(ShrinkToFit)稍微復(fù)雜一點(diǎn)。代碼的主要思路是:每次調(diào)整字體大小、行距或邊距之后,檢查一下CurPageCount屬性,看看是否已經(jīng)達(dá)到目標(biāo)頁(yè)數(shù)。如果已經(jīng)達(dá)到,調(diào)整過(guò)程結(jié)束,Execute方法返回True;如果調(diào)整之后頁(yè)數(shù)變得太多(或太少),例如縮小字體之后頁(yè)數(shù)小于目標(biāo)頁(yè)數(shù),則撤消最后一次操作,嘗試另一種調(diào)整頁(yè)數(shù)的辦法。當(dāng)所有調(diào)整頁(yè)數(shù)的辦法都已經(jīng)試遍,而頁(yè)數(shù)仍未能達(dá)到要求,則Execute返回False。
建議至少用字體和行距兩種辦法調(diào)整文檔的頁(yè)數(shù),這樣可以大大增加調(diào)整成功的可能性。當(dāng)然,不能排除未能達(dá)到目標(biāo)頁(yè)數(shù)的情形出現(xiàn),導(dǎo)致這種情形的主要原因可能是文檔包含太多手工插入的分頁(yè)符、大型圖片,或者是因?yàn)槟繕?biāo)頁(yè)數(shù)和現(xiàn)有頁(yè)數(shù)的差距太大。
三、設(shè)計(jì)用戶界面
前面介紹了調(diào)整文檔頁(yè)數(shù)的核心思路和代碼。下面來(lái)看看制作用戶界面的過(guò)程。用戶界面主要包括兩部分:菜單和對(duì)話框。圖六是加入到“文件->打印預(yù)覽”前面的“調(diào)整頁(yè)數(shù)”菜單。
圖六:“調(diào)整頁(yè)數(shù)”菜單
“調(diào)整頁(yè)數(shù)”菜單包括三個(gè)選項(xiàng)。第一個(gè)選項(xiàng)允許指定目標(biāo)頁(yè)數(shù),然后根據(jù)默認(rèn)的參數(shù)執(zhí)行調(diào)整操作。第二個(gè)選項(xiàng)等同于Word的“減少一頁(yè)”功能,但原來(lái)這個(gè)功能只能在打印預(yù)覽狀態(tài)下使用。第三個(gè)選項(xiàng)顯示出圖二的對(duì)話框,用戶自定義調(diào)整頁(yè)數(shù)的參數(shù),然后點(diǎn)擊“確定”按鈕開(kāi)始調(diào)整頁(yè)數(shù)。如果用戶試圖調(diào)整文檔頁(yè)數(shù)時(shí),文檔沒(méi)有保存,會(huì)出現(xiàn)圖七的提示。
圖七:調(diào)整頁(yè)數(shù)之前保存文檔
設(shè)置菜單的代碼和其他代碼一起保存在一個(gè)插件模板DocSizer.dot之中。DocSizer.dot的主要內(nèi)容如圖八所示。其中:
- frmDocSizer窗體:包含圖二的對(duì)話框。
- Interface模塊:包括生成圖六菜單、根據(jù)默認(rèn)參數(shù)調(diào)整文檔頁(yè)數(shù)、顯示圖二對(duì)話框的代碼。
- Context類模塊:處理上下文信息。
- DocSizer類模塊:實(shí)現(xiàn)調(diào)整文檔頁(yè)數(shù)的核心功能。
圖八:DocSizer模板的主要內(nèi)容
DocSizer.dot必須放入Word的自動(dòng)啟動(dòng)目錄。對(duì)于Windows 2000/XP和Office 2000/XP,啟動(dòng)目錄通常是\Documents and Settings\<用戶名字>\Application Data\Microsoft\Word\STARTUP。Word會(huì)自動(dòng)加載該目錄下的模板,這樣我們就可以在Word啟動(dòng)時(shí)加入“調(diào)整頁(yè)數(shù)”菜單。
因篇幅關(guān)系,這里不再介紹Context類模塊和Interface模塊的代碼,但你可以參見(jiàn)本文的附件DocSizer.dot,代碼中包含了詳細(xì)的注釋。將DocSizer.dot安裝到Word的啟動(dòng)目錄下,啟動(dòng)Word就可以看到“文件->打印預(yù)覽”前面增加了一個(gè)“調(diào)整頁(yè)數(shù)”菜單。啟動(dòng)目錄的具體位置,可查看Word菜單“工具->選項(xiàng)”再選擇“文件位置”。如果你要查看DocSizer.dot的完整代碼,先按正常方式打開(kāi)它,然后選擇菜單“工具->宏->宏”,再選擇“編輯”即可。
作為一種通用軟件,Word無(wú)法照顧到每一個(gè)用戶的特殊要求和使用習(xí)慣。但是,Word提供了VBA編程支持和完善的對(duì)象模型。正如本文例子所顯示的,利用這些技術(shù),我們可以隨心所欲地定制Word,提高工作效率。