2.3        套打功能

常见的打印就是将打印内容,打印在一张白纸上,而套打则不同,它是把一些内容打印到已经印好的单据上,比如,快递单,增值税发票等。

 

套打有个最常见,也是最难解决的问题:对齐。

 

JCP的解决之道是提供开发时对齐功能、运行时对齐功能:

开发时对齐

提供打印模板设计器,开发人员可以利用这个工具,导入套打底图,在可视化的环境中,拖放对齐,最后得到 HTML模板代码。

运行时对齐

最终用户可以使用连续打印偏移调整和打印位置的运行时调整,解决对齐的问题。

提示:

我们还提供一种运行时的模板设计器,让最终用户可以创建,修改打印模板,不过,这是本公司的另外一个产品,叫点点打印,相关说明可参考:

http://bbs.jatools.com/viewthread.php?tid=2660&extra=page%3D2

 

2.3.1    打印模板设计器

开发人员可以利用这个工具,导入套打底图,在可视化的环境中,拖放对齐,最后得到 HTML模板代码。工具界面如下:

 

 

设计工具地址:http://d.jatools.com

相关文档:http://bbs.jatools.com/viewthread.php?tid=2655&extra=page%3D2

 

得到模板代码后,你可以用你所用的语言,填充其中动态的内容。

提示:

你可以自己写HTML模板代码,而不必借助这个工具。

2.3.2    打印位置的运行时调整

打印位置的运行时调整

有时,即使是同一套程序,同一个页面,在不同的打印机上,打印出来的相对位置也有差别,有的打印机打印出来的内容凑得紧些,有的则离得开些,这种偏差不能通过设置打印机边距的方式进行调整。

 

借助JCP的打印位置的运行时调整,使用户可以自行调整打印内容的位置,并保存到注册表,下次打印时,JCP会自动使用新的位置打印。 这种微调后的位置信息只保存在本地注册表中,因此不会影响到其他用户的打印,这对有大量前台打印,并有不同类型打印机打印同一种票据的场合,非常实用。

 

你可以将 myDoc.ui属性设置成 draggable进入带拖放调整的打印预览界面,如下:

1.  var myDoc = {  

2.      // 进入位置调整功能的打印预览式,即带"拖放调整..."按钮  

3.      ui : "draggable",   

4.      settings : {  

5.          paperWidth : 210,  

6.          paperHeight : 140,  

7.          orientation : 1  

8.      },  

9.      documents : document,  

10.     noMargins : true,  

11.     // 必须设置一个id,否则JCP不知道调整后的位置,保存到注册表的哪一项中  

12.     settingsId : 'mydoc2',   

13.     copyrights : "杰创软件拥有版权  www.jatools.com"  

14. }  

15. getJCP().printPreview(myDoc);  

执行这述代码,会出现如下打印预览界面,注意,比普通打印预览多出了一个拖放调整按钮:

 

 

点击拖放调整按钮,可以进入调整界面,如下:

 

如果预览界面中有多页,在拖放界面中,也只取第一页的数据来做调整,可调整内容包括字型,字体大小,位置,但不能调整显示框大小。先选中一个可调整项,再拖动位置,或者用工具栏中的字体、字号变大变小按钮来设置。

 

点击确定即将当前修改,保存到注册表并退出,点取消,则不保存退出。

 

提示:

打印页面中有很多对象,有些可拖放,有些不可拖放,JCP如何知道?

 

同时满足如下条件的对象,JCP认为是可拖放对象:

1.page1 div中的直接子对象;

2.该子对象有id属性

3.该子对象绝对定位,即 position:absolute;

1.  <style>  

2.      /*确保子对像绝对定位*/  

3.      .child-abs >div {  

4.          position: absolute;  

5.      }  

6.      /*子对像初始位置*/  

7.      #d1{left:195px;top:323px;}  

8.      #d2{left:136px;top:150px;}  

9.      #d3{left:264px;top:224px;}  

10. </style>  

11. <div id="page1" class="child-abs" style='position:relative;width:210mm;height:140mm;'>  

12.      <!--<img>没有id,因此不可调整-->  

13.     <img class='screen-only' src="pj.jpg" style='width:100%;height:100%;'/>  

14.     <div id='d1'>423051702880563</div>  

15.     <div id='d2'>13850775557</div>  

16.     <div id='d3'>30.00</div>  

17. </div>  

本例中,page div的直接子对象,有一个<img>和三个<div>,因为<img>没有id,因此不能调整,三个<div>id,并因为代码中的34511,四行代码确保其为绝对定位,所以是可拖整项。

 

注意,不应将调整项的初始位置,应设置到<style>中,而不应设置到style中,否则拖放后的位置不会生效,如:

1.  <div id="page1" ...>  

2.       <!--错误,因left,right设置到了 style属性中,调整后的位置不会生效-->  

3.       <div id='d1' style='left:10px;top:200px;'/>423051702880563</div>  

4.      ...  

5.  </div>  

2.3.3    连续打印的套打偏移校正

连续打印的套打偏移校正连续打印的套打偏移校正2

套打程序经常出现上下偏移的问题,如图所示:

                     

 

导致偏移的原因有两种:

1.       是打印纸张高度设置得不对,只要根据误差,调整纸张高度就行了。

2.       打印机走纸不够精准,少打几页还看不出有什么问题,但连续打印后,因为误差累积起来,打印到10几张时,就很明显了,如果打印到100多张,上千张,必然谬之毫厘,差之千里了。

 

一般地,在打印多页后,如果出现向下偏移的情况,说明纸张高度设置过大了,调小一点即可,如果出现向上偏移的情况,说明纸张高度过小,调大一点即可。但这里有个坏消息,比如,进过测试,发现如果纸张高度设置为 200.1mm向下偏移,如果设成200.0mm向上偏移,很简单,设成它们俩的中间值:200.05mm试试。遗憾的是,windows不接受这个值,因为windows能接受的纸张高度,其精度只能达到0.1mm,即使你设置了这个中间值,打印机可能仍然以两值中的一个进行打印,也就是说,你设了这个中间值,打印仍然会存在偏移!

 

好消息是,JCP采用插入校正页的方法,可完美解决这个问题,图示如下:

JCP启动一个打印任务,当打印完几张正常高度的票据后,打印一张用来纠偏的、特别高度的票据(以下称之为校正页),这样可以降低对打印机走纸精度的要求,也达到了纠偏的目的。

 

用以下步骤设置一个可插入校正页的打印任务:

1. 先测量出,票据的实际高度,比如120mm()*100mm();

2. 按所测票据大小,设置自定义纸张:

1.  var myDoc = {  

2.      settings : {  

3.          paperWidth : 120, // 以毫米为单位   

4.          paperHeight : 100  

5.      },  

6.      settingsId : 'mydoc1'// 必须设置一个唯一文档id   

7.  }  

 

当发现有连续偏移时,只要调用 setupNormalOffset 方法,设置相应的校正参数即可:

1.  getJCP().setupNormalOffset('mydoc1');// 唯一参数,标识对哪一个打印文档进行校正设定  

此方法将使控件弹出如下对话框:

 

你打印了多少张:表示你用来测试的页数,测试页数越多,误差越大,校正效果越好。

共偏移了多少毫米(向上偏移为负):表示你经过上一参数连续打印后,第一页与最后一页的偏移距离,以毫米为单位,当向下偏移时,设置为正,反之为负,也可以设置一个小数位。

每隔几张插入一个校正页:表示校正页的插入频度。此参数建议在5~15之间为好。

清除:可能换了好的打印机,不需要校正了,那就采用此按钮,清除校正设置。

确定:设置完了,保存。

取消:即不保存,也不清除,退出。

 

如果你设置了校正参数,按确定以后,控件将在本地注册表中保存这些参数,当下一次myDoc.settingsId mydoc1 的打印启动时,JCP将按这些参数自动插入校正页。

 

JCP打印与校正设置的示例代码:

1.  function doPrint() {  

2.      var myDoc = {  

3.          settings : {  

4.              paperWidth : 1200,  

5.              paperHeight : 1000  

6.          },  

7.          settingsId : 'mydoc1',  

8.          documents : document,  

9.          copyrights : '杰创软件拥有版权  www.jatools.com'  

10.     }  

11.     getJCP().print(myDoc, false); // 直接打印  

12. }  

13. function doNormalOffset() {  

14.     getJCP().setupNormalOffset('mydoc1'); // 设置校正参数  

15. }}  

16. ...  

17. <intput type='button' value='打印' onclick='doPrint()'>  

18. <intput type='button' value='偏移校正设置' onclick=' doNormalOffset ()'>  

19. ...  

 

提示:

1.上述代码还不够完美,因为,代码中出现两个按钮,一个是打印,一个是偏移校正,这个偏移校正按钮,对于大多数不存在偏移问题的用户来说,可能永远用不上,即使有少数用户存在偏移问题,也只需要设置一次,就可以了。这个按钮有点多余,下面是改进后的代码:

1.  function doPrint() {  

2.      if (window.event.shiftKey) {  

3.          getJCP().setupNormalOffset('mydoc1'); // 设置校正参数      

4.      } else {  

5.          var myDoc = {  

6.              settings : {  

7.                  paperWidth : 1200,  

8.                  paperHeight : 1000  

9.              },  

10.             settingsId : 'mydoc1',  

11.             documents : document,  

12.             copyrights : '杰创软件拥有版权  www.jatools.com'  

13.         };  

14.         getJCP().print(myDoc, false);  

15.     }  

16. }  

17. ...  

18. <intput type='button' value='打印' onclick='doPrint()'>  

19. ...  

删除了用于校正的按钮,但doPrint代码里,加入了是否按下shift键的判断,如果用户在按下打印按钮的同时,也按了shift,则调用控件的校正设定方法,否则,就以正常打印处理。 这样,作为程序开发人员,只需要当用户发现有连续偏移时,才告诉他使用这个方法,来校正偏差。

 

2.因为校正参数是按myDoc.settingsId来保存的,所以不会干扰到其他打印。

3.因为校正参数是保存在用户的本地注册表中,所以某一个用户的校正设置,不会影响到其他用户的。

 

2.3.4    零边距打印

忽略页边距打印

每个打印机都会有一个最小边距(最小边距因打印机不同而不同),如果你在纸张设置对话框中,设置的边距小于这个最小边距,那么,你的设置将不会起作用。这使你在套打时会产生这样的问题:你已经设置了最小的左()边距,但打印出来的东西,仍然是偏右(偏下)。这时,你可以设置 myDoc.noMargins属性为true 在此模式下,JCP将强制上、下、左、右边距为零,而打印预览时,页面设置对话框中的边距设置变为不可用,设置零边距的代码如下:

 

1.  var myDoc = {  

2.      noMargins : true,//设置为零边距打印  

3.      documents : document,  

4.      copyrights : '杰创软件拥有版权  www.jatools.com'  

5.  };  

6.  getJCP().print(myDoc);  

 

在零边距打印模式下,页面中的打印内容定位,可使用 page divpadding-leftpadding-top来整体移动被打印内容,实现相当于设置左、上边距的效果。

 

2.3.5       仅在预览时可见,不输出到打印机的套打底图

底图仅在预览时可见,不输出到打印机

套打时,一般会先扫描事先印好的票据底图,便于对齐及预览,但打印时(调用print方法,或者调用printPreview方法后,按其中的打印按钮时),不希望把底图打印到打印机,这时,你可以设置myDoc.enableScreenOnlyClass true,在底图的那个<img>对象上,设置其screen-only样式类即可:

 

1.  <script>  

2.  ...  

3.      //打印文档对象  

4.      var myDoc = {  

5.          // 使所有使用 screen-only 样式类的对象,只在预览、显示时可见,打印时隐藏  

6.          enableScreenOnlyClass : true,   

7.          documents : document,  

8.          copyrights : '杰创软件拥有版权  www.jatools.com'  

9.      };  

10.     getJCP().print(myDoc);  

11. ...  

12. </script>  

13. ...  

14. <div id="page1">  

15.     <img src="dt.jpg" class='screen-only'>  

16.     <div>培训费</div>  

17.     ...  

18. </div>  

只要设置了myDoc.enableScreenOnlyClass true 则实际打印时,page div 中所有样式类为screen-only的元素,自动被设置为不可见 display:none

 

2.3.6    表格线预览时可见,打印时不可见(控制显示、打印输出样式)

表格线预览时可见,打印时不可见(控制显示、打印输出样式)

当你在myDoc.enableScreenOnlyClasstrue时,实际打印时(调用print方法,或者调用printPreview方法后,按其中的打印按钮时)JCP会在打印页的div外,套一个有jatools-printing 样式类div容器,如:

1.  <div id=page1>...</div>  

2.  <div id=page2>...</div>  

被套jatools-printing 样式类容器时的情形:

1.  <div class='jatools-printing'>  

2.     <div id=page1>...</div>  

3.     <div id=page2>...</div>  

4.  </div>  

利用这个特点,就可以灵活地定制出,显示与打印的不同样式,如表格线在预览时可见,打印时不可见:

1.  <script>  

2.      ...  

3.      var myDoc = {  

4.          enablePrintingClass : true,// 使JCP打印时,套上 jatools-printing  

5.          documents : document,  

6.          copyrights : '杰创软件拥有版权  www.jatools.com'  

7.      };  

8.      getJCP().print(myDoc);  

9.      ...  

10. </script>  

11. <style>  

12. #sample td {  

13.     border: solid 1px black;  

14. }  

15. /*打印时,单元格边框设置为白色,即不可见*/  

16. .jatools-printing #sample td {  

17.     border: 0px solid white;  

18. }  

19. </style>  

20. ...  

21. <div id='page1'>  

22.     <table id='sample'>...</table>  

23. </div>  

 

当预览时,因为不存在 jatools-printing 类,所以根据<style>里的设置,单元格边框显示为solid 1px black

当打印时,因为page1外,存在有 jatools-printing 类的容器,因此,同样根据<style>里的设置,单元格边框显示为solid 0px white,即不可见。

 

实际上,上一节的打印时底图不可见,也可以通过本节所述方法实现。

2.3.7    录入后打印

录入后打印

有这样一种打印需求,用户希望在录入一些数据后,即把该单据打印出来,比如以下页面,既有打印按钮,又有一些文本输入框,或下拉选择框,或者checkbox,但不希望打印时,把它们的边框打印出来,那么可以使用本功能。

 

如录入界面如下:

 

使用本功能后预览效果:

 

使用本功能,你可以用以下代码:

1.  <html>  

2.  <head>  

3.  <script type="text/javascript" src="jcp.js"></script>  

4.  <style type="text/css">  

5.    

6.  .jatools-page input[type=text] {  

7.      border: none;  

8.      background-color: transparent;  

9.  }  

10.   

11. </style>  

12. <script type="text/javascript">  

13.     function doPrint(how) {  

14.         var myDoc = {  

15.             inputs : true, //录入打印  

16.             settings : {  

17.                 paperName : 'A4'  

18.             },  

19.             noMargins : true,  //无边距打印  

20.             documents : document,  

21.             enableScreenOnlyClass : true,  // 确保 42行的图片不会被打印出来

22.             copyrights : "杰创软件拥有版权  www.jatools.com"  

23.         }  

24.         var jcp = getJCP();  

25.         if (how == '打印预览...')  

26.             jcp.printPreview(myDoc, false);  

27.   

28.         else if (how == '打印...')  

29.             jcp.print(myDoc, true);  

30.   

31.         else  

32.             jcp.print(myDoc, false);  

33.     }  

34. </script>  

35. </head>  

36. <body>  

37.     ...  

38.     <input type="button" value="打印预览..." onClick="doPrint('打印预览...')">  

39.     <input type="button" value="打印..." onClick="doPrint('打印...')">  

40.     <input type="button" value="打印" onClick="doPrint('打印')">  

41.     <div id='page1' style="position: relative;; width: 210mm; height: 297mm;">  

42.         <img src="image/sqs2.jpg" style="position: absolute; width: 100%; height: 100%" class="screen-only">  

43.         <input type="text" style="position: absolute; width: 520px; left: 209px; top: 181px;" />  

44.         <input type="checkbox" style="position: absolute; left: 295px; top: 350px;" />  

45.         ...  

46.     </div>  

47. </body>  

48. </html>  

 

6行代码,设置一个样式规则,让文本输入框在打印预览或者打印时,显示成无边框,透明。在JCP打印预览,或者打印时,会自动在 page1 上设置样式类 jatools-page,因此,打印和预览时,这条规则会起作用,在录入界面中,这条规则不起作用,因此,行 43 <input> 以文本输入框的普通样式显示,一般是有边框,且白色背景。

 

15行代码,设置 myDoc.inputs true录入后打印,可以确保录入的信息能够打印出来。

 

提示:

1.  利用 jatools-page 样式类来创建样式规则,可以让输入组件在打印时,呈现与录入时不同的显示效果;

2.  如果想在打印成功后,保存打印状态到后台,可以用 done 回调,详见下节。

 

2.4        打印回调

JCP在打印后,会回调你的js函数,在回调函数里,你可以处理一些打印后的任务,比如,往服务器写入一些标志,或者,重新启动一次打印任务。

2.4.1    打印结束回调脚本

打印结束回调脚本

1.  var myDoc = {  

2.      documents : document,  

3.      copyrights : '杰创软件拥有版权  www.jatools.com'  

4.  };  

5.  //定义回调方法            

6.  myDoc.done = function() {  

7.      console.log("打印结束.")  

8.  }  

9.  getJCP().print(myDoc);  

JCP中,所有调用都是异步执行的,print方法也一样,该方法返回时,打印可能还没有结束,当打印结束时(指打印任务已经生成),JCP会检查myDoc上是否定义了done回调函数,如果有,则调用之。

 

回调的主要用处:

ü  打印结束后通过 ajax写入已打印标志到数据库,避免重复打印等;

ü  可以一次打印多个文档,并使用不同的参数,比如,一键打印到不同打印机。

 

注意,打印结束是指打印任务已经生成,并不是指打印机已经完成打印。即使你的打印机处于关机状态,JCP也会调用done,只不过,打印任务仅列在打印机任务列表中,等待发往打印机而已。

 

也就是说,你不能用done来判断是否真的打印出来了。

 

JCP不允许连续调用 print方法, 但你可以在done回调里,再次调用print方法。

 

错误的二次打印

1.  var myDoc1 = {...};    

2.  getJCP().print(myDoc1);    

3.  var myDoc2 = {...};    

4.  getJCP().print(myDoc2); // 连续打印,错误 !!!  

5.                          // 结果不可预知,有可能myDoc1被打印两次,而myDoc2不打印,  

6.                          // 或者,myDoc1 不打印, myDoc2 被打印两次,  

7.                          // 或者 myDoc2 myDoc1先打印  

 

正确的二次打印:

1.  var myDoc1 = {  

2.      ...  

3.      done : function() {  

4.           var myDoc2 = {  

5.              ...  

6.          };  

7.          getJCP().print(myDoc2);  

8.      }  

9.  };  

10. getJCP().print(myDoc1);  

采用done多次打印时,会生成多个系统打印任务。

 

2.4.2    一键打印到不同打印机

一键打印到不同打印机

1.  function doPrint() {  

2.      var myDoc1 = {  

3.          settings : {  

4.              printer : 'oki 5330'  

5.          },  

6.          documents : 'pages1.jsp',  

7.          copyrights : '杰创软件拥有版权  www.jatools.com',  

8.          done : function() {  

9.              var myDoc2 = {  

10.                 settings : {  

11.                     printer : 'hp laser jet 1000'  

12.                 },  

13.                 documents : 'pages2.jsp',  

14.                 copyrights : '杰创软件拥有版权  www.jatools.com',  

15.                 done : function() {  

16.                     console.log("打印结束");  

17.                 }  

18.             };  

19.             getJCP().print(myDoc2);  

20.         }  

21.     };  

22.     getJCP().print(myDoc1);  

23. }  

 

本例利用回调函数done,将文档 pages1.jsppages2.jsp两个文档中的page1page2...,分别打印到 okihp打印机。

 

这里的打印机参数,是直接写成常量,实际项目中,你可以使用JCPgetPrinters取得打印机列表,并把它们显示在<select> 中,便于用户选择需要的打印机。

 

正如上节所说,本例使用回调来进行第二次打印,而不是采用连续调用。

提示:

虽然你可以将 myDoc.documents设置成数组,同时打印这两个文档,如下所示,但这种情况下,两个文档的所有打印参数是一样的,比如,同样的输出打印机,同样的纸张等等:

1.  function doPrint() {    

2.      var myDoc1 = {    

3.          settings : {    

4.              printer : 'oki 5330'  // 只能都打印到oki打印机  

5.          },    

6.          documents : ['pages1.jsp',  'pages2.jsp']  

7.          copyrights : '杰创软件拥有版权  www.jatools.com'  

8.      };    

9.      getJCP().print(myDoc1);    

10. }    

 

2.4.3    一键打印多个 pdf html 文档

一键打印多个 pdf 和 html 文档

JCP 可以用 print方法,打印HTML文档,也可以用 printDocument方法,打印一个pdf文件,而且这两个方法,都提供了回调机制。

 

类似print方法,printDocument的第二个参数中,也可以设置一个回调函数,如下所示:

1.  var myDoc = {  

2.      fileType : 'pdf',  

3.      done : function() {  

4.          console.log("pdf打印结束");  

5.      }  

6.  }  

7.  getJCP().printDocument("a.pdf", myDoc);  

这里你只需要关注 done回调,更详细的pdf打印介绍,请参照pdf打印部分。

 

以下示例,利用回调机制,一次性顺序打印一个HTML文档,一个pdf文档,再打印HTML文档:

1.  //打印三个文档,html格式2个,pdf格式1  

2.  var docs = [{  

3.      type : 'html',  

4.      documents : document  

5.          // HTML文档, page1 ... div在本文档中  

6.      }, {  

7.      type : 'pdf'// pdf文件打印  

8.      url : 'pdf/apicpp.pdf' // pdf流位置  

9.  }, {  

10.     type : 'html',  

11.     documents : 'pages.htm' // HTML文档, page1 ... div在一个url文件中  

12. }]  

13. function main() {  

14.     doPrint(0);  

15. }  

16. function doPrint(current) {  

17.     var doc = docs[current];  

18.     if (doc.type == 'html') {  

19.         var mydoc = {  

20.             documents : doc.documents,  

21.             copyrights : "杰创软件拥有版权  www.jatools.com",  

22.             done : function() {  

23.                 if (current < docs.length - 1) {  

24.                     doPrint(current + 1);  

25.                 }  

26.             }  

27.         }  

28.         getJCP().print(mydoc);  

29.     } else if (doc.type == 'pdf') {  

30.         var mydoc = {  

31.             fileType : 'pdf',  

32.             done : function() {  

33.                 if (current < docs.length - 1) {  

34.                     doPrint(current + 1);  

35.                 }  

36.             }  

37.         }  

38.         getJCP().printDocument(doc.url, mydoc);  

39.     }  

40. }