精华内容
下载资源
问答
  • 如何实现用户自定义Word模板

    千次阅读 2014-08-15 11:19:32
    导读: 在涉及到word文档生成的项目中,一般采用编程将数据填充到word模板中生成文件的实现方式,如果模板由开发人员自己设计,那么编程填充数据是相对容易实现的;但如果用户希望可以自己修改模板或自己定义新模板...
    

    导读:  在涉及到word文档生成的项目中,一般采用编程将数据填充到word模板中生成文件的实现方式,如果模板由开发人员自己设计,那么编程填充数据是相对容易实现的;但如果用户希望可以自己修改模板或自己定义新模板,并且又不需要开发人员针对新模板重写代码,那么应该使用怎样的技术来实现这种需求呢?本文就此问题展开论述。

     

             在实际的开发过程中,针对导出生成word文档的需求,都是用程序填充数据到word模板中来实现的。所谓模板也就是标记了数据位置和字体段落样式的Word文件。一般来说,模板中的数据可以分为两种:一种是一对一的,一个数据在模版中对应一个数据位置,比如一个模板只需要使用“部门、姓名、原因、天数、日期”5个数据,每个数据只需要在文件中使用一次,如下图模板所示:

     


    用户定义模板时可以使用全部数据,也可以使用5个数据中的任意4个、3个甚至1个,但模板中数据标签的数量总是这个集合的子集。

     

             另一种是一对多,一个数据在同一个模版中可以使用一次,也可以使用多次。例如下图的介绍信的模板,每一个数据都需要在文件中出现两次。


     


    如果一个项目系统中所有的模板都是固定的,那么只需要在系统开发过程中由开发人员和用户一起把模板做好,之后,开发人员根据业务逻辑编写程序,给模板中的数据位置填充具体的数据即可实现,但在实际的应用中,很多时候不是这样的,最终用户还是希望能自己随时新建和修改模板,以满足不断变化的业务需求,如果每次模板的变化都需要和开发人员一起来完成,那么这个项目就永远不会完工。

             为了满足用户的这一需求,在项目中就需要提供一个模板制作和管理的模块,又为了让程序可以控制和识别用户定义模板中的数据位置,那么就需要开发人员来制作一个约定,让最终用户在新建或编辑模板时必须按照约定来制作模板。那么应该如何约定呢? PageOffice提供的解决方案就是使用书签和特殊格式的文本来对文档中需要插入数据的位置做标记。

            

    第一种方法使用书签来标记数据位置Word文档中插入书签的方法:把光标定位到需要标记数据位置的地方,点Word菜单中的“插入”-“书签”,就会弹出一个标题为“书签”的对话框,输入新书签的名称,书签名可以包含数字但中间不能有空格,用PageOffice开发的时候不推荐使用中文命名书签名。注意:如果新插入位置或新对象采用的是已有的书签名,原有的书签将自动取消,所以使用书签来标记数据位置的话,肯定是一个数据对应模板中一个位置的一对一模式。

    在使用PageOffice开发的过程中,为了避免出现与用户自己定义的书签出现冲突,要求插入的书签名称必须以“PO_”开头。注意是字母o,不是数字0。书签名是不区分大小写的也可以写成“po_”。在PageOffice的概念里提到的数据区域,本质上就是书签,但是只有“po_”开头的书签才叫数据区域(DataRegion),请大家注意这点。

     

    第二种方法就是使用特殊格式的文本来标记数据位置,比如说:【合同日期】、【##合同日期##】、[*合同日期*]……等等。使用书签标记数据位置有一个明显的缺点,同一个书签名称在一个word文档中只能出现一次,也就是说一个数据区域在文档中肯定是唯一的,但是很多时候模版中需要多处位置使用同样的数据变量,例如上面举例使用的“合同日期”可能就需要在一个合同中多个位置出现,使用数据区域肯定是无法满足需求的,但是使用特殊格式的文本来标记就没有这种限制了。

    在PageOffice的概念里,这种【合同日期】、【##合同日期##】、[*合同日期*]……等等特殊格式的文本都可以被认为是数据标签(DataTag),同一个数据标签可以在一份文件中多个位置出现多次,动态填充数据标签生成文件的时候,同一个数据标签都会被同样的数据替换。

    注意:【合同日期】和【##合同日期##】是两个不同的数据标签,同一个数据标签一定要是文本格式完全一致,比如:【##合同日期##】和【##合同日期##】虽然字体颜色和大小都不一样,但是文本内容是完全一样的,就被认为是同一个数据标签,所以在模版制作的时候定义数据标签是很简单的,只需要插入同样格式的文本就可以了。

     

    虽然以上的两点约定已经定好了,但是让用户在编辑模版的时候使用office自身的功能来制作和编辑模版,还是步骤繁琐、困难重重,制作的模板也容易出现一些问题,为此,PageOffice提供了定义模板的接口,由开发人员使用程序预先定义好用户可以使用的数据区域和数据标签,当用户编辑模版的时候,给用户弹出一个数据区域和数据标签的选择窗口,用户只需要选择使用这些数据区域和数据标签插入到word模版中,设置好数据的段落格式、字体、样式、颜色等等。这样以来,不但处理好了约定的问题,而且使得用户自定义模板的操作更加简单快捷。

     

    一、使用PageOffice提供的编辑模版功能:

             PageOffice给开发人员提供了定义模版的接口DefineDataRegionDefineDataTag方法,PageOffice.WordWriter.WordDocument.Template.DefineDataRegion

    PageOffice.WordWriter.WordDocument.Template.DefineDataTag

         1. 使用DefineDataRegion定义数据区域,例如ASP.NET代码如下:

           PageOffice.WordWriter.WordDocument doc =new

                               PageOffice.WordWriter.WordDocument();

           doc.Template.DefineDataRegion("Name","[姓名 ]");

           doc.Template.DefineDataRegion("Address","[地址 ]");

           doc.Template.DefineDataRegion("Tel","[电话 ]");

            doc.Template.DefineDataRegion("Phone","[手机 ]");

           doc.Template.DefineDataRegion("Sex","[性别 ]");

           doc.Template.DefineDataRegion("Age","[年龄 ]");

           doc.Template.DefineDataRegion("Email","[邮箱 ]");

           doc.Template.DefineDataRegion("QQNo","[ QQ]");

           doc.Template.DefineDataRegion("MSNNo","[ MSN]");

     

             或者用Java开发的话,代码如下:

           WordDocument doc = newWordDocument();

           doc.getTemplate().defineDataRegion("Name", "[姓名 ]");

           doc.getTemplate().defineDataRegion("Address", "[地址 ]");

           doc.getTemplate().defineDataRegion("Tel", "[电话 ]");

           doc.getTemplate().defineDataRegion("Phone", "[手机 ]");

           doc.getTemplate().defineDataRegion("Sex", "[性别 ]");

           doc.getTemplate().defineDataRegion("Age", "[年龄 ]");

           doc.getTemplate().defineDataRegion("Email", "[邮箱 ]");

           doc.getTemplate().defineDataRegion("QQNo", "[ QQ ]");

           doc.getTemplate().defineDataRegion("MSNNo", "[ MSN ]");

             开发人员用服务器端程序定义好用户可使用的数据区域,用户在客户端编辑模版的时候就可以使用这些数据区域。注意,这里的代码中不需要写PO_开头,PageOffice会自动添加这个前缀。用户编辑模版时看到的数据区域管理窗口,如下图所示:

     

     

     

             左侧“待添加数据区域”列表是可以用户目前可以使用的数据区域,右侧“已添加数据区域”列表是文档中已经添加的数据区域。此窗口的实现代码已经由PageOffice封装完毕,无需开发人员自己写复杂的js+html代码去实现,并且此窗口中内容的样式是可以修改的,如果对那些样式不太满意,只需要对此窗口html代码的样式做简单的调整即可。用户编辑数据区域时的效果,如下图所示:

            

     

        Word文档中已经添加过的数据区域都会出现在“已添加数据区域”的列表中,word文档中显示的是DefineDataRegion方法第二个参数的值。这些插入到模版中的数据区域就如方法一中手动插入的书签完全一样,也是带PO_开头的书签。使用此方法就可以实现用户自定义模版的功能,开发人员只管编写程序给数据区域赋值对应的数据,用户自己定义模版的样式、数据位置和数据的多少,用户可以使用全部的数据区域,也可以只使用部分, PageOffice在生成文件的时候,会自动忽略没有使用的数据区域,而不需要开发人员做任何代码的调整。

     

     



      2. 使用DefineDataTag定义数据标签,例如ASP.NET的代码如下:

            PageOffice.WordWriter.WordDocument doc =new

                            PageOffice.WordWriter.WordDocument();

           doc.Template.DefineDataTag("{甲方 }");

           doc.Template.DefineDataTag("{乙方 }");

           doc.Template.DefineDataTag("{担保人 }");

           doc.Template.DefineDataTag("合同日期");

           doc.Template.DefineDataTag("合同编号");

             或者用Java开发的代码如下:

                       WordDocument doc = newWordDocument();

             doc.getTemplate().defineDataTag("{甲方}");

                       doc.getTemplate().defineDataTag("{乙方}");

                       doc.getTemplate().defineDataTag("{担保人 }");

                       doc.getTemplate().defineDataTag("合同日期");

                       doc.getTemplate().defineDataTag("合同编号");

             开发人员用服务器端程序定义好用户可使用的数据标签,用户在客户端编辑模版的时候就可以使用这些数据标签。用户编辑模版时看到的数据标签管理窗口,如下图所示:

            

     

    同数据区域一样,对此窗口的实现代码,PageOffice也已经封装完毕,无需开发人员自己写复杂的js+html代码去实现,并且此窗口中内容的样式是可以修改的,如果对那些样式不太满意,只需要简单的调整一下此窗口html代码中的样式即可。开发人员只管编写程序给数据标签赋值对应的数据,用户自己定义模版的样式、数据位置和数据的多少,用户可以使用全部的数据区域,也可以只使用部分, PageOffice在生成文件的时候,会自动忽略没有使用的数据标签,而不需要开发人员做任何代码的调整。

    与数据区域的管理不同的是,由于数据标签在文件中不是唯一的,所以不管在文件中添加了多少个数据标签,在数据标签管理窗口中的数据标签都是不会减少的。

     

    二、使用PageOffice.WordWriter命名空间中的对象填充数据到Word模版,动态生成文档:

     

    .WordDocument.OpenDataRegion 方法

    .WordDocument.OpenDataTag 方法

     

    开发人员只需要使用上面的两个方法,针对word模版编写程序,给所有的数据区域和数据标签赋值相应的数据即可,无需关心模版中到底使用了多少个数据区域和数据标签,那些Word模版中从来没有使用过的数据区域和数据标签,PageOffice会自动忽略,而无需开发人员做任何代码的修改,从而完美实现用户自定义模板的需求。

    ASP.NET开发的赋值代码如下,

     

            PageOffice.WordWriter.WordDocument doc =new  

                                 PageOffice.WordWriter.WordDocument();

           doc.OpenDataRegion("Name").Value="张三";       

           doc.OpenDataRegion("Age").Value="21";

          ……

           doc.OpenDataTag("{甲方公司名称 }").Value ="微软中国总部";

           doc.OpenDataTag("{乙方公司名称 }").Value ="北京幻想科技公司";

          ……

       PageOfficeCtrl1.SetWriter(doc);

     

    Java开发的赋值代码如下:

     

             WordDocument doc = new WordDocument();

           doc.openDataRegion("Name").setValue("张三");       

           doc.openDataRegion("Age").setValue("21"); 

            ……

            doc.openDataTag("{甲方公司名称 }").setValue("微软中国总部");

            doc.openDataTag("{乙方公司名称 }").setValue( "北京幻想科技公司");

            ……

            poCtrl.setWriter(doc);

     

             详细请参考PageOffice示例代码Samples中“综合演示”目录下的示例TemplateEdit.rar的运行效果。或者从下面的链接下载单独的TemplateEdit.rar示例:

             ASP.NEThttp://www.zhuozhengsoft.com/smalldemo/TemplateEdit_ASP.NET.rar

             Javahttp://www.zhuozhengsoft.com/smalldemo/TemplateEdit_java.rar

    展开全文
  • PageOffice--实现用户自定义Word模板

    千次阅读 2018-09-12 14:19:50
    导读: 在涉及到word文档生成的项目中,一般采用编程将数据填充到word模板中生成文件的实现方式,如果模板由开发人员自己设计,那么编程填充数据是相对容易实现的;但如果用户希望可以自己修改模板或自己定义新模板...

    导读: 在涉及到word文档生成的项目中,一般采用编程将数据填充到word模板中生成文件的实现方式,如果模板由开发人员自己设计,那么编程填充数据是相对容易实现的;但如果用户希望可以自己修改模板或自己定义新模板,并且又不需要开发人员针对新模板重写代码,那么应该使用怎样的技术来实现这种需求呢?本文就此问题展开论述。

    在实际的开发过程中,针对导出生成word文档的需求,都是用程序填充数据到word模板中来实现的。所谓模板也就是标记了数据位置和字体段落样式的Word文件。一般来说,模板中的数据可以分为两种:一种是一对一的,一个数据在模版中对应一个数据位置,比如一个模板只需要使用“部门、姓名、原因、天数、日期”5个数据,每个数据只需要在文件中使用一次,如下图模板所示:

    1710

    用户定义模板时可以使用全部数据,也可以使用5个数据中的任意4个、3个甚至1个,但模板中数据标签的数量总是这个集合的子集。

    另一种是一对多,一个数据在同一个模版中可以使用一次,也可以使用多次。例如下图的介绍信的模板,每一个数据都需要在文件中出现两次。

    1711

    如果一个项目系统中所有的模板都是固定的,那么只需要在系统开发过程中由开发人员和用户一起把模板做好,之后,开发人员根据业务逻辑编写程序,给模板中的数据位置填充具体的数据即可实现,但在实际的应用中,很多时候不是这样的,最终用户还是希望能自己随时新建和修改模板,以满足不断变化的业务需求,如果每次模板的变化都需要和开发人员一起来完成,那么这个项目就永远不会完工。
    为了满足用户的这一需求,在项目中就需要提供一个模板制作和管理的模块,又为了让程序可以控制和识别用户定义模板中的数据位置,那么就需要开发人员来制作一个约定,让最终用户在新建或编辑模板时必须按照约定来制作模板。那么应该如何约定呢? PageOffice提供的解决方案就是使用书签和特殊格式的文本来对文档中需要插入数据的位置做标记。

    第一种方法使用书签来标记数据位置。Word文档中插入书签的方法:把光标定位到需要标记数据位置的地方,点Word菜单中的“插入”-“书签”,就会弹出一个标题为“书签”的对话框,输入新书签的名称,书签名可以包含数字但中间不能有空格,用PageOffice开发的时候不推荐使用中文命名书签名。注意:如果新插入位置或新对象采用的是已有的书签名,原有的书签将自动取消,所以使用书签来标记数据位置的话,肯定是一个数据对应模板中一个位置的一对一模式。
    在使用PageOffice开发的过程中,为了避免出现与用户自己定义的书签出现冲突,要求插入的书签名称必须以“PO_”开头。注意是字母o,不是数字0。书签名是不区分大小写的也可以写成“po_”。在PageOffice的概念里提到的数据区域,本质上就是书签,但是只有“po_”开头的书签才叫数据区域(DataRegion),请大家注意这点。

    第二种方法就是使用特殊格式的文本来标记数据位置,比如说:【合同日期】、【##合同日期##】、[合同日期]……等等。使用书签标记数据位置有一个明显的缺点,同一个书签名称在一个word文档中只能出现一次,也就是说一个数据区域在文档中肯定是唯一的,但是很多时候模版中需要多处位置使用同样的数据变量,例如上面举例使用的“合同日期”可能就需要在一个合同中多个位置出现,使用数据区域肯定是无法满足需求的,但是使用特殊格式的文本来标记就没有这种限制了。

    在PageOffice的概念里,这种【合同日期】、【##合同日期##】、[合同日期]……等等特殊格式的文本都可以被认为是数据标签(DataTag),同一个数据标签可以在一份文件中多个位置出现多次,动态填充数据标签生成文件的时候,同一个数据标签都会被同样的数据替换。

    注意:【合同日期】和【##合同日期##】是两个不同的数据标签,同一个数据标签一定要是文本格式完全一致,比如:【##合同日期##】和【##合同日期##】虽然字体颜色和大小都不一样,但是文本内容是完全一样的,就被认为是同一个数据标签,所以在模版制作的时候定义数据标签是很简单的,只需要插入同样格式的文本就可以了。

    虽然以上的两点约定已经定好了,但是让用户在编辑模版的时候使用office自身的功能来制作和编辑模版,还是步骤繁琐、困难重重,制作的模板也容易出现一些问题,为此,PageOffice提供了定义模板的接口,由开发人员使用程序预先定义好用户可以使用的数据区域和数据标签,当用户编辑模版的时候,给用户弹出一个数据区域和数据标签的选择窗口,用户只需要选择使用这些数据区域和数据标签插入到word模版中,设置好数据的段落格式、字体、样式、颜色等等。这样以来,不但处理好了约定的问题,而且使得用户自定义模板的操作更加简单快捷。

    一、 使用PageOffice提供的编辑模版功能:

    PageOffice给开发人员提供了定义模版的接口DefineDataRegion和DefineDataTag方法,

    • PageOffice.WordWriter.WordDocument.Template.DefineDataRegion
    • PageOffice.WordWriter.WordDocument.Template.DefineDataTag

    1. 使用DefineDataRegion定义数据区域,例如Java代码如下:
            WordDocument doc = new WordDocument();
            doc.getTemplate().defineDataRegion("Name", "[ 姓名 ]");
            doc.getTemplate().defineDataRegion("Address", "[ 地址 ]");
            doc.getTemplate().defineDataRegion("Tel", "[ 电话 ]");
            doc.getTemplate().defineDataRegion("Phone", "[ 手机 ]");
            doc.getTemplate().defineDataRegion("Sex", "[ 性别 ]");
            doc.getTemplate().defineDataRegion("Age", "[ 年龄 ]");
            doc.getTemplate().defineDataRegion("Email", "[ 邮箱 ]");
            doc.getTemplate().defineDataRegion("QQNo", "[ QQ号 ]");
            doc.getTemplate().defineDataRegion("MSNNo", "[ MSN号 ]");
    

    或者用ASP.NET开发的话,代码如下:

    	    PageOffice.WordWriter.WordDocument doc = new PageOffice.WordWriter.WordDocument();
            doc.Template.DefineDataRegion("Name", "[ 姓名 ]");
            doc.Template.DefineDataRegion("Address", "[ 地址 ]");
            doc.Template.DefineDataRegion("Tel", "[ 电话 ]");
            doc.Template.DefineDataRegion("Phone", "[ 手机 ]");
            doc.Template.DefineDataRegion("Sex", "[ 性别 ]");
            doc.Template.DefineDataRegion("Age", "[ 年龄 ]");
            doc.Template.DefineDataRegion("Email", "[ 邮箱 ]");
            doc.Template.DefineDataRegion("QQNo", "[ QQ号 ]");
            doc.Template.DefineDataRegion("MSNNo", "[ MSN号 ]");
    

    开发人员用服务器端程序定义好用户可使用的数据区域,用户在客户端编辑模版的时候就可以使用这些数据区域。注意,这里的代码中不需要写PO_ 开头,PageOffice会自动添加这个前缀。用户编辑模版时看到的数据区域管理窗口,如下图所示:

    1712

    左侧“待添加数据区域”列表是可以用户目前可以使用的数据区域,右侧“已添加数据区域”列表是文档中已经添加的数据区域。此窗口的实现代码已经由PageOffice封装完毕,无需开发人员自己写复杂的js+html代码去实现,并且此窗口中内容的样式是可以修改的,如果对那些样式不太满意,只需要对此窗口html代码的样式做简单的调整即可。用户编辑数据区域时的效果,如下图所示:

    1713

    1. 使用DefineDataTag定义数据标签,例如Java的代码如下:
    		WordDocument doc = new WordDocument();
            doc.getTemplate().defineDataTag("{ 甲方 }");
    		doc.getTemplate().defineDataTag("{ 乙方 }");
    		doc.getTemplate().defineDataTag("{ 担保人 }");
    		doc.getTemplate().defineDataTag("【 合同日期 】");
    		doc.getTemplate().defineDataTag("【 合同编号 】");
    

    或者用ASP.NET开发的代码如下:

            PageOffice.WordWriter.WordDocument doc = new PageOffice.WordWriter.WordDocument();
            doc.Template.DefineDataTag("{ 甲方 }");
            doc.Template.DefineDataTag("{ 乙方 }");
            doc.Template.DefineDataTag("{ 担保人 }");
            doc.Template.DefineDataTag("【 合同日期 】");
            doc.Template.DefineDataTag("【 合同编号 】");
    

    开发人员用服务器端程序定义好用户可使用的数据标签,用户在客户端编辑模版的时候就可以使用这些数据标签。用户编辑模版时看到的数据标签管理窗口,如下图所示:

    1714

    同数据区域一样,对此窗口的实现代码,PageOffice也已经封装完毕,无需开发人员自己写复杂的js+html代码去实现,并且此窗口中内容的样式是可以修改的,如果对那些样式不太满意,只需要简单的调整一下此窗口html代码中的样式即可。开发人员只管编写程序给数据标签赋值对应的数据,用户自己定义模版的样式、数据位置和数据的多少,用户可以使用全部的数据区域,也可以只使用部分, PageOffice在生成文件的时候,会自动忽略没有使用的数据标签,而不需要开发人员做任何代码的调整。

    与数据区域的管理不同的是,由于数据标签在文件中不是唯一的,所以不管在文件中添加了多少个数据标签,在数据标签管理窗口中的数据标签都是不会减少的。

    二. 使用PageOffice.WordWriter 命名空间中的对象填充数据到Word模版,动态生成文档:

    • PageOffice.WordWriter.WordDocument.OpenDataRegion 方法
    • PageOffice.WordWriter.WordDocument.OpenDataTag 方法

    开发人员只需要使用上面的两个方法,针对word模版编写程序,给所有的数据区域和数据标签赋值相应的数据即可,无需关心模版中到底使用了多少个数据区域和数据标签,那些Word模版中从来没有使用过的数据区域和数据标签,PageOffice会自动忽略,而无需开发人员做任何代码的修改,从而完美实现用户自定义模板的需求。

    Java开发的赋值代码如下:

    	    WordDocument doc = new WordDocument();
            doc.openDataRegion("Name").setValue("张三");        
            doc.openDataRegion("Age").setValue("21");  
    		……
            doc.openDataTag("{ 甲方公司名称 }").setValue("微软中国总部"); 
            doc.openDataTag("{ 乙方公司名称 }").setValue( "北京幻想科技公司"); 
    		……
            poCtrl.setWriter(doc);
    

    ASP.NET开发的赋值代码如下,

            PageOffice.WordWriter.WordDocument doc = new PageOffice.WordWriter.WordDocument();
            doc.OpenDataRegion("Name").Value = "张三";        
            doc.OpenDataRegion("Age").Value = "21";
    		……
            doc.OpenDataTag("{ 甲方公司名称 }").Value = "微软中国总部";
            doc.OpenDataTag("{ 乙方公司名称 }").Value = "北京幻想科技公司";
    		……
            PageOfficeCtrl1.SetWriter(doc);
    

    详细请参考PageOffice开发包里Samples4中的相关示例演示:
    二、30、用户自定义模板中数据区域(DataRegion)的位置(专业版、企业版)
    二、31、用户自定义模板中数据标签(DataTag)的位置(专业版、企业版)
    三、12、实现“用户自定义Word模板”动态生成文件(专业版、企业版)

    展开全文
  • 大家好!时值端午,虽然假期只有...这不,昨天一位朋友就跟我说:老师在群里发了一套初一代数的例题模板(Word文件),让家长自己在此基础上,随便修改每道题的数字系数和加减号,以便同学反复练习整式化简的技巧。听...

    f527e2e19ca84b1e6860050951af4ffc.png

    大家好!时值端午,虽然假期只有三天,但也可以让大家在紧张的工作中稍微透一口气。不过对于已经在电脑前度过一个学期的孩子们来说,小长假恐怕也放松不得,因为马上就要进入疫情后的第一次期末考试了。

    孩子考试,家长当然也不会轻松。这不,昨天一位朋友就跟我说:老师在群里发了一套初一代数的例题模板(Word文件),让家长自己在此基础上,随便修改每道题的数字系数和加减号,以便同学反复练习整式化简的技巧。

    94b8b69fb9c359ac201d566f252c5706.png

    听到这里,杨老师马上明白了他的意思:能不能想个办法,自动修改上面这个 word 文件中每一道题的数字系数和加减号,然后对它们随机修改,从而生成无穷无尽的练习题,比如下面这页:

    7c74f16c3e2c0f99beab98ddedd1415a.png

    因为这个问题非常适合使用 Word VBA 解决,所以今天我们就聊一聊这个实用的小程序 —— 怎样用 Word VBA 随机“改题”。

    从朋友的叙述可知,这个任务包括两个要求:(1)随机改变加减号,也就是正负号(2)随机改变多项式的数字系数。相对而言,加减号的实现思路比较简单,所以咱们就从它开始。

    还是我们在《全民一起VBA 基础篇》中反复强调的那个思维:如果不知道怎样写程序,就看看我们人类自己处理这个问题时,会遵循怎样的步骤。

    比如对于修改加减号的操作,如果是我们自己手动解决,那么相必会是这样的流程:

    1. 让眼睛定位到第一行

    2. 从左向右读取每一个字符

    3. 如果发现该字符是一个加号或者减号,就停下来执行步骤 4,否则回到第2步继续读取下一个字符

    4. 如果发现是加减号并停下来,那么马上抛一个硬币,如果硬币正面朝上,就把它写成加号、如果背面朝上就写成减号,不管它以前是加号还是减号

    5. 如上反复,直到读完一行所有字符,就回到第1步再读取下一行。

    如果各位对上述流程没有异议,那么我们就可以用一模一样的方式写出一个VBA程序。只不过对于其中“定位某一行”、“读取一个字符”、“抛硬币”三个环节,需要用到一点Word对象用法知识和随机数技巧:

    技巧1:读取Word文档的每一段

    前面的第1步“读取每一行”,在Word中对应的是“读取每一个段落”。我们在《全民一起VBA 提高篇》里学过:当前打开的Word文档(docx文件)在VBA中表示为 ActiveDocumen 对象,而Document类的对象都有一个集合性质的属性 Paragraphs,代表该文档中的所有段落。

    所以,我们可以使用 For each p in ActiveDocument.Paragraphs 的方式,依次扫描当前文档中的每一段。每次循环时,循环变量 p 都是一个 Paragraph(段落)对象,代表当前扫描到的那个段落。框架代码如下:

    ee4072365cbf804d919cbd882d0b8d8c.png

    技巧2:读取一段中的每个字符并修改

    Paragraph(段落)对象有一个Range属性,代表该段落的所有内容,包括其中每一个字符以及它们的格式等等。其中 Range.Characters属性代表的就是该段落中的所有字符,Range.Characters(i) 就是其中第 i 个字符,而 Range.Characters.Count 则代表这一段字符的总数量

    所以,使用下面的循环就可以读取每一个段落中的每一个字符,并且将它们都改成 “*”:

    26777ae7fbece60d8e1defc9b93bb8ee.png

    技巧3:“抛硬币”决定加减号

    学过《提高篇》的同学一定都记得“随机数”这个概念,显然,抛硬币就是最经典的随机变量问题。我们知道,VBA中可以使用 rnd() 函数生成一个0到1之间的随机小数,所以只要调用 rnd() 生成一个随机数,然后判断它是否大于0.5 —— 如果大于则返回“+”、否则返回“-”即可。

    这里为了简化代码,杨老师使用了一个《全民一起VBA》中没有介绍过的函数 IIF 来表示随机返回加减号的过程:

    7380034cd5e5ddb853c777cf81c3350c.png

    IIF函数其实就是一个简化版的if语句,与Excel表格公式中的IF函数非常相似:假如第一个参数 Rnd()>0.5 为True,那么就返回第二个参数“+”,否则返回第三个参数“-”。因此上面语句执行后,s 就是一个随机的加号或减号。

    攻克了上述三个技巧,稍加组合,VBA代码就已经呼之欲出了:

    373b5330f21429180ffcc2b558c94f70.png

    上面的代码基本就是前面三个技巧的组合使用,具体参见代码中的注释即可。运行之后,果然所有加减号都被随机处理,下面就是杨老师运行后的截图示例:

    4c86822fd9adac07f2dc6e97a0177adc.png

    ukd

    dbba0efa68a74bfd77331864a35c795f.gif

    解决了加减号,接下来就可以解决数字的随机化。整体思路当然也与加减号一样,可以逐个扫描每一段落的每一个字符,如果发现是数字字符,就把它换成一个随机数字字符。

    但是别急,咱们先观察一下原来的内容,会发现其中有三个场合会出现数字:(1)题目序号(2)多项式系数比如第一题中的23、15、8 等 (3)指数,比如第一题中a的3次方、c的2次方等。而在这三种场合中,只有(2)多项式系数是需要随机修改的、其他应该保持不变。

    60ccedf5033c1cd8aa209ddbba30c19f.png

    那么怎样排除掉(1)和(2)两种情况呢?其实也不难。对于(1)题目序号,因为源文档使用的是Word“项目编号”功能,不会被认作段落中的内容字符,因而p.Range.Characters里面根本扫描不到它,所以我们完全可以忽略不管。

    而对于出现在(2)“指数”中的数字,则与多项式中的数字系数一样,实实在在是 Range.Characters 中的一员,所以必须要找出来并排除掉。

    正规的排除方法,应当是判断一个数字是否出现在加减号、括号、空格等分隔符之后、同时又位于本项的第一个字母之前,所以使用正则表达式更为合理,不过这样做比较复杂。事实上,本例的Word文档中有一个捷径可以利用:所有作为指数的数字,其字体格式都是“上标”。

    dc1e65832c7256642302844ff4ebad9e.png

    而在Word中,如果我们想知道某一段(用对象 p 代表)的第i个字符的字体,那么只要用 r=p.Range 得到 p 中所有内容范围,接下来可以使用下面的代码实现:

    04d428d286b425ca12225f4b448e0303.png

    而在Word的Font对象中,又有一个 SuperScript 属性和 SubScript属性,分别代表这个内容的字体格式是否为上标或下标。假如 Font.SuperScript 是 -1 ,则说明是上标格式,0 则说明不是上标。

    所以把上面这个判断也加到前面处理加减号的循环中,我们的程序就大功告成了:

    b9b7bb0ced33ca846b81aadc92a8c044.png

    程序运行,稍等片刻,所有习题果然连参数带正负号都被随机修改。这一次朋友再也不担心孩子没题可做了 —— 无论你小子做题多么快,老爸只要一按按钮,你就得从头再来200道!

    17160c958250371e820f10fffa572797.png

    当然,因为我们走了一个“捷径”,所以还是会产生一些遗留问题不便处理。比如随机数字只有1-9,没有考虑0;而且有时候还会出现下面这种“不专业”的随机系数:

    1259569bfcc8982742d153855afb222a.png

    对于这些问题,根本的解决方案是按照数学规范中对“系数”的定义去分析文本,比如“位于一个项的第一个字母之前、若干位连续数字、1可以省略 …… ”,大家有兴趣可以尝试改进。而今天这篇文章只是抛砖引玉,毕竟十几行代码就已经基本解决了随意改题的需求,虽有瑕疵但也足堪使用。反正大过节的,咱就不较真了吧 7e3654efbf77285610ccb43111d3c461.png

    祝大家节日快乐!

    ukd

    00ccf4026cbfc9bd45e6ddac9bf0efa6.gif

    更多精彩阅读

    b5c81bcc7b1c6f44e5540d1d8d268ff9.gif

    接下来,我们会怎么走 —— 关于新的课程和教学方式

    不变的,是初心 —— 写在又一门课程收尾之际

    为什么又是游戏?—— 摘一段二十多年前的青涩文章

    44ed446b19aee320e16b4bd0812cbb90.png

    扫码听课

    杨老师课程全集

    全民一起玩Python

    全民一起VBA

    欢迎加入、一起进步

    展开全文
  • 文章 ID:890702最后更新日期:2004年11月28日版本:1.2本页内容概要更多信息概要公司有各种制作好的业务合同Word模板,但在填写合同时,经常会由于疏忽,使合同的内容被修改。要是能让合同填写人只在文档的指定位置...

    How to: 怎样保护Word文档的部分内容?

    文章 ID:890702
    最后更新日期:2004年11月28日
    版本:1.2
    本页内容
    概要概要
    更多信息更多信息

    概要

    公司有各种制作好的业务合同Word模板,但在填写合同时,经常会由于疏忽,使合同的内容被修改。要是能让合同填写人只在文档的指定位置填写内容就好了,其他位置不允许修改。Word的文档保护功能可以帮助我们。

    更多信息

    从“工具”菜单选择“保护文档”,在任务窗格里显示相关设置,如图1所示。选中“仅允许在文档中进行此类编辑”,采用默认选项“未作任何更改”,表示任何人打开文档都是只读状态,不能修改文档内容。现在,需要指定哪些内容允许用户修改。首先,在文档中选中所有允许修改的部分,例如合同中的所有下划线部分(可以按住Ctrl键跳选)。然后,在任务窗格中选中“例外项”下的“每个人”(如果在企业局域网的域里面,还可以单击“更多用户”,指定个别用户的权限)。最后,单击“是,启动强制保护”按钮,显示对话框,如图2所示。设置密码后,单击“确定”。这样,任何人(或指定域用户)打开文档时,都只能在上述指定位置输入或修改内容。
    ---------------------
    (来源:http://support.microsoft.com/default.aspx?scid=kb;zh-cn;890702)
    展开全文
  • ">怎样才能让扩展的模板中的内容也立即更新</span>? <strong>----html:----------------------------</strong> <br>var html = '<div style="width:100%; font-size:12px;">' + '<table width=...
  • word使用技巧大全

    热门讨论 2011-03-18 20:37:53
    修改Word2000标尺 20 ★微调各边距 20 ★用键盘选定表格中的项目 20 ★巧用Alt键调整表格 21 ★修改表格的垂直对齐方式 21 ★将公式完整显示出来 21 ★增加、删除和显示全部菜单命令 21 ★摒弃“智能菜单”功能 22...
  • C# winform典型系统开发模板

    热门讨论 2011-09-17 15:13:21
     4.2.4 怎样操作RichtextBox控件的选择文本 82  4.2.5 如何获取数据表中字段的描述信息 83  4.3 设计过程 83  4.3.1 获取数据表中字段的中文信息 84  4.3.2 添加数据表的查询条件 86  4.3.3 ...
  • 学习Python操作word文件,使用render()方法时报错ValueError: can only parse strings。 2、相关代码 ``` # _*_ encoding:utf-8 _*_ from docxtpl import DocxTemplate data_dic = { 't1':'燕子', 't2':'...
  • PageOffice--实现用户自定义Word模板 ...导读: 在涉及到word文档生成的项目中,一般采用...但如果用户希望可以自己修改模板或自己定义新模板,并且又不需要开发人员针对新模板重写代码,那么应该使用怎样的...
  • 实例018 修改可执行文件中的资源 1.3 程序调试 实例019 创建调试程序 实例020 在Release版本中进行调试 实例021 在VC中如何进行远程调试 实例022 利用简单断点进行程序调试 实例023 利用条件断点进行程序调试...
  • 实例018 修改可执行文件中的资源 1.3 程序调试 实例019 创建调试程序 实例020 在Release版本中进行调试 实例021 在VC中如何进行远程调试 实例022 利用简单断点进行程序调试 实例023 利用条件断点进行程序调试...
  • 您公司的某个商品要卖给不同的客户,而客户有时会提供他自己的相应货号,报价或做出口合同时,怎样找到该客户对应的的货号呢,传统的方法是把以前所有有关该客户的报价,订单统统找一遍。《外贸专家》为您解决了这...
  • python3.x Opencv Toturial

    2018-03-01 12:59:34
    而 Python 的悄 然兴起给他们带来的希望,如果说 C++ 是 tex 的话,那 Python 的易用性 相当于 word。他们可以很快的看懂本书的所有代码,并可以学着使用它们 来解决自己的问题,同时也能拓展自己的视野。别人经常说...
  • 14. 判断文档是否正在被修改 13 15. 在只读的方式下返回($$return 13 16. 刷新表单 14 17. 怎样在文档里存照片? 14 18. 后台lotusscript如何取得前台表单中复选框所选择的项目列表(b/s结构) 15 19. 试图的列公式...
  • 测试培训教材

    2014-04-01 12:10:48
    8.选择标准模板字段映射(一般默认选择) 9. 把QC中的需求字段和需求模版的列名所对应的字母标号进行关联映射。 从Excel导入 选Demo项目,提示错误: 改成用alice_qc用户登录即可! ...
  • C++MFC教程

    热门讨论 2013-05-21 13:37:15
    SetAt 修改指定位置的CString对象 InsertAt 在某一位置插入CString对象 常用宏 RGB TRACE ASSERT VERIFY 常用函数 CWindApp* AfxGetApp(); HINSTANCE AfxGetInstanceHandle( ); HINSTANCE AfxGetResourceHandle( ...
  • asp.net知识库

    2015-06-18 08:45:45
    HttpModule 实现 ASP.Net (*.aspx) 中文简繁体的自动转换,不用修改原有的任何代码,直接部署即可! 服务器自定义开发二之客户端脚本回发 Web开发: 使用URL重写WEB主题切换 如何在Asp.Net1.1中实现页面模板(所谓的...
  • 你可以按照以下几点来修改自己的简历: <ol><li> 控制简历页数在 2 页以下,简历不是写得越长越牛逼,而是用内容去吸引人家的。 </li><li> 按照用人方的要求以及自身具备但别人不怎么会的领域去写...
  • C#编程经验技巧宝典

    热门讨论 2008-06-01 08:59:33
    C#编程经验技巧宝典源代码,目录如下: 第1章 开发环境 1 <br>1.1 Visual Studio开发环境安装与配置 2 <br>0001 安装Visual Studio 2005开发环境须知 2 <br>0002 配置合适的Visual Studio 2005...
  • JAVA 正则表达式

    热门讨论 2010-01-15 11:16:37
    正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 自从 jdk1.4 推出 java.util.regex 包,就为我们提供了很好的 JAVA 正则表达式应用平台。 因为正则表达式是一个很庞杂的体系,所以我仅例举些...

空空如也

空空如也

1
收藏数 20
精华内容 8
关键字:

怎样修改word模板