基于VBA组卷中自动排版的实现
发布时间:2010/8/2 10:41:36 来源:城市学习网 编辑:ziteng
一、引言
建立完善的题库是课程建设的一项重要工作,当数据库的形式进行题库管理,通过编写抽题程序,在分类明确、题量丰富的题库支持下,实现自动组卷并非难事。试卷一般都采用Word文档,若采用VBA编程,要用程序将试题写入到Word文档,可以通过引用 Microsoft Word 9.0 Object Library中的相关对象来实现:图片、图形、文本框及艺术字等可利用Shapes集合对象的相应方法加入到文档中;表格也可以通过Tables集合对象的Add 方法加入,其大小、位置等排版信息都可以以参数的形式传入;而文字部分的内容也能以字符串的形式通过调用Content对象的InsertAfter方法插入,排版时对其字型、字体、字号及段落格式则可以利用Font对象及Paragraph对象的属性或方式进行设置。
选择题是各类试卷中经常出现的题型,而它的排版有其特殊性,因为选择题的四个选项根据其长度有可能排成四段(行),也可能排成两行,每行两个选项,且它对段落缩进及上、下行中选项的对齐等都有一定的要求。
这里要解决的几个问题是:
1.题干部分的题号对齐,尤其是一位数题号与两位数题号(如第9题与第10题);前、后题题干内容的第一个字符对齐;题干部分作为段落要采用悬挂缩进、且缩进量应合适。
2.若选项由四段(行)构成,则每段应有左缩进、缩进量与题干部分的悬挂缩进量相同,同时,选项内容的长度也有可以超过一行(如第10题中的选项C),所以对选项也要设置悬挂缩进、且缩进量应合适。
3.若选项由两行构成(如第11题中的四个选项),则上一行的选项C与下一行的选项D应对齐。
二、定义选择题的数据结构
程序设计中为了便于将选择题作为函数的参数传递,应定义选择题的数据类型的结构,选择题的结构通常由题干及四个选项构成,具体定义如下:
Public Type Choice
Sentence As String '题干内容,不包括题号
ChoiceA As String '选项A的内容
ChoiceB As String '选项B的内容
ChoiceC As String '选项C的内容
ChoiceD As String '选项D的内容
End Type
三、页面设置与段落格式
首先进行页面设置,页面上边距、下边距、左边距、右边距分别设为1英寸、1英寸、1.25英寸、1.25英寸, 默认制表位长度为0.33英寸。
With ActiveDocument.PageSetup
.TopMargin = InchesToPoints(1)
.BottomMargin = InchesToPoints(1)
.LeftMargin = InchesToPoints(1.25)
.RightMargin = InchesToPoints(1.25)
End With
ActiveDocument.DefaultTabStop = InchesToPoints(0.33)
为了对题干部分进行排版,先自定义一个过程insTabIndent,其功能是根据第一个参数str1传入的题干内容及第二个参数Num传入的本题题号,在题干内容前加上题号,若Num为0,则表示不加题号;在题号后设置一个制表位,使前、后题的题干内容的第一个字符对齐;对题干所在段落设置悬挂缩进一个制表。
Private Sub insTabIndent(str1 As String, Num As Integer)
Dim s As String
If Num < 10 Then s = " " + Trim(str(Num)) + "." Else s = Trim(str(Num)) + "."
If Num = 0 Then s = ""
Set myRange = appObj.ActiveDocument.Content
myRange.Collapse Direction:=wdCollapseEnd
myRange.InsertAfter s & vbTab & str1
myRange.InsertParagraphAfter
myRange.Font.Name = "宋体"
myRange.Font.Size = 12
myRange.ParagraphFormat.TabHangingIndent 1 '悬挂缩进1个制表位
End Sub
为了对选项进行排版,自定义一个过程insLeftAndHangingIndent,其功能是根据参数str1传入的选项内容,将其作为段落写入Word文档,设置字型、字体、字号及左缩进和悬挂缩进。
Private Sub insLeftAndHangingIndent(str1 As String)
Set myRange = ActiveDocument.Content
myRange.Collapse Direction:=wdCollapseEnd
myRange.InsertAfter str1
myRange.InsertParagraphAfter
myRange.Font.Name = "宋体"
myRange.Font.Size = 12'小四
'设置左缩进与悬挂缩进
myRange.ParagraphFormat.FirstLineIndent = CentimetersToPoints(-0.64)
myRange.ParagraphFormat.LeftIndent = CentimetersToPoints(1.48)
End Sub [NextPage] 四、选择题的写入及排版
如果四个选项按四段(行)进行排版,则只要通过调用前面所定义的两个过程就能实现,但四个选项要按两行排版则有两种方法可供选择:一是分节分栏法:将四个选项按四段写入Word文档,并将它们设置成单独的一节,再采用分成两栏的方法实现;二是直接写入排版法:在同一行的两个选项之间插入若干个制表位实现对齐,编程中将涉及写入点的定位问题。
1、分节分栏法
选择题写入Word文档及排版操作在自定义过程insSelect中实现,传入参数mObj内封装了一道选择题;题号通过参数n传入;参数max传入的值是选项内容字符数的临界值,即当四个选项内容中字符数最多者如果超过了max,则四个选项排版成四段(行),否则排成两行。其中用到的函数maxLen(mObj)返回值表示选择题mObj的四个选项内容中字符数的最大值。
Private Sub insSelect(mObj As Choice, ByRef n As Integer, max As Integer)
insTabIndent mObj.Sentence, n '写入题干内容及题号
If maxLen(mObj) > max Then'按四段(行)并采用左缩进及悬挂缩进写入
insLeftAndHangingIndent "A) " + mObj.ChoiceA
insLeftAndHangingIndent "B) " + mObj.ChoiceB
insLeftAndHangingIndent "C) " + mObj.ChoiceC
insLeftAndHangingIndent "D) " + mObj.ChoiceD
ActiveDocument.Content.InsertParagraphAfter
n = n + 1
Else '选项按缩进一个制表位形式写入,为后面的分节分栏做准备
Set tempRange = ActiveDocument.Content
tempRange.Collapse Direction:=wdCollapseEnd
tempRange.InsertAfter vbTab & "A) " & mObj.ChoiceA
tempRange.InsertParagraphAfter
tempRange.InsertAfter vbTab & "B) " & mObj.ChoiceB
tempRange.InsertParagraphAfter
tempRange.InsertAfter vbTab & "C) " & mObj.ChoiceC
tempRange.InsertParagraphAfter
tempRange.InsertAfter vbTab & "D) " & mObj.ChoiceD
tempRange.InsertParagraphAfter
tempRange.Font.Name = "宋体"
tempRange.Font.Size = 12'小四
n = n + 1 '题号增1,为写入下一题做准备
tempRange.Select '选定四个选项所在的区域
If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
ActiveWindow.Panes(2).Close
End If
If ActiveWindow.ActivePane.View.Type <> wdPrintView Then
ActiveWindow.ActivePane.View.Type = wdPrintView
End If[NextPage] '在选定区域的起始位置和末尾位置插入分节符
ActiveDocument.Range(Start:=Selection.Start, End:=Selection.Start). _
InsertBreak Type:=wdSectionBreakContinuous
Selection.Start = Selection.Start + 1
ActiveDocument.Range(Start:=Selection.End, _
End:=Selection.End).InsertBreak Type:=wdSectionBreakContinuous
'将选定的文本分成两栏
With Selection.PageSetup.TextColumns
.SetCount NumColumns:=2
.EvenlySpaced = True
.LineBetween = False
.Width = CentimetersToPoints(6.95)
.Spacing = CentimetersToPoints(0)
End With
ActiveDocument.Content.InsertParagraphAfter
End If
End Sub
2、直接插入排版法
这种方法是将选项A与选项C作为同一行写入、选项B与选项D作为同一行写入,关键在于要求上一行的C选项与下一行的D选项要求对齐,定位方法是在选项A的末尾与选项C、选项B的末尾与选项D之间插入若干个制表位,模拟手工调整的方法进行对齐。但上、下行要分别插入多少个制表位才能对齐呢?这要借助于Selection对象的Information属性进行检测。Selection.Information(wdHorizontalPositionRelativeToPage)可以返回指定的所选内容或区域的水平位置,该位置是所选内容或区域的左边与页面的左边之间的距离,以磅为单位(72磅 = 1英寸)。具体方法是每插入一个制表位就将选定区域收缩为选定区域后一个字符,同时检测它距页面的左边之间的距离,直到距离达到某个设定值时就停止插入。具体程序如下:
insTabIndent "A) " + mObj.ChoiceA, 0 '写入选项A
x = appObj.ActiveDocument.Content.Paragraphs.Count – 1
'x记录下选项A所在的段落数
'每次循环插入一个制表位,并在循环条件中进行位置检测
Do
Set tempRange = appObj.ActiveDocument.Range(appObj.ActiveDocument.Content.Paragraphs(x). _
Range.End - 1, appObj.ActiveDocument.Content.Paragraphs(x).Range.End)
tempRange.Select
Selection.TypeText vbTab '在选项A的内容后插入一个制表位
Set tempRange = appObj.ActiveDocument.Range(appObj.ActiveDocument.Content.Paragraphs(x). _
Range.End - 1, appObj.ActiveDocument.Content.Paragraphs(x).Range.End)
tempRange.Select '选定区域设为当前区域的最后位置
Loop While (Selection.Information(wdHorizontalPositionRelativeToPage) < 280)
'当检测到写入点位置距与页面左边的距离超过280磅时停止插入制表位
Selection.TypeText "C) " + mObj.ChoiceC '写入选项C
'以下处理下一行的选项B和选项D,方法同上
insTabIndent "B) " + mObj.ChoiceB, 0 '写入选项B
x = appObj.ActiveDocument.Content.Paragraphs.Count - 1
Do
Set tempRange = appObj.ActiveDocument.Range(appObj.ActiveDocument.Content.Paragraphs(x). _
Range.End - 1, appObj.ActiveDocument.Content.Paragraphs(x).Range.End)
tempRange.Select
Selection.TypeText vbTab
Set tempRange = appObj.ActiveDocument.Range(appObj.ActiveDocument.Content.Paragraphs(x). _
Range.End - 1, appObj.ActiveDocument.Content.Paragraphs(x).Range.End)
tempRange.Select
Loop While (Selection.Information(wdHorizontalPositionRelativeToPage) < 280)
Selection.TypeText "D) " + mObj.ChoiceD '写入选项D
appObj.ActiveDocument.Content.InsertParagraphAfter
五、结语
前述两种选择题的排版方式均已在实际的试卷自动生成系统的排版应用中进行实测,测试表明两种方法都能得到较为规范、美观的排版效果。分节分栏法实现思想较为简单,但由于生成的文档中有大量的分节符,如果对于生成的文档要作手工调整,可能会带来一点麻烦;直接插入排版法的好处是不分节,便于后期的手工调整,但生成文档的速度稍慢。
参考文献
1.Microsoft Word 2000 Visual Basic 对象模型帮助系统[DK]
2.孟祥瑞. Visual Basic 6.0程序设计[M]. 华东理工大学出版社,2005