zoukankan      html  css  js  c++  java
  • Web系统页面打印技术实现与分析

    1 Web页面打印概述
    应用WEB化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于WEB的应用,客户端的规则很简单,容易学习,容易维护,容易发布。在WEB系统中,打印的确是个烦人的问题。 要么自己开发打印控件,如果项目时间紧,肯定来不及。这对程序员来说,因为浏览器的局限性,却要面对很多挑战。怎么样来进行基于WEB的套打,就是这么一个令多数程序员头痛不已的问题。 基于WEB的套打,难度在于要将浏览器中呈现的HTML,精确地打印到票据中,而且能够实现对分页位置的控制。
    本文将介绍常用的Web打印与套打方案,同时提供一些免费的打印控件,供大家学习参考。
    2 常用Web页面打印方案
    2.1 浏览器的打印功能
    这种方案的优势是不需要对浏览器作任何扩充,是最简单的办法,但问题也最多,如:
    1. 不能精确分页。
    浏览器一般是根据用户设置的页面大小,web页面的内容多少,来自行决定分页位置,程序员很难控制。会有页脚页眉干扰。
    2. 不能准确对齐边边距及打印文字。
    3. 不能解决连续打印。
    比如,不是仅打印一张票据,而是连续一次打印若干个票据。
    2.2 使用PDF文件
    用这种方式,就是从服务器端下载一个pdf文件流,在IE中用adobe插件打开,然后用adobe的打印菜单进行打印,虽然这种方案,也能实现精确套打,但需要下载adobe插件。这是国外报表工具经常推荐的一种打印方法,但在pdf不那么普及的中国,这种方案不是最好选择。
    2.3 采用Applet方式
    采用Applet方式,分页或精确打印,都可以做到完美,但缺点也很明显,表现在:
    1. 安装Applet成本巨大。需要下载十几M的文件。
    Applet本身可能并不大,但运行Applet所需的jre一般至少10几M(jre1.4.2 , 15.45M)。用户需要极大的耐心,来进行打印。
    2. 打印报表时,需要重新向服务器检索数据,效率低。
    因为Applet方案,一般采用html方式呈现数据,打印时Applet必须向服务器检索同一张票据的数据,看上去,是打印了当前页的票据,实际上,Applet根本不会用当前html页的数据来打印,而是向服务器下载数据到Applet中来打印。也就是说,打印的话,必须两次请求,一次html呈现,一次用来打印。
    市场上java类的报表工具,一般推荐Applet方式来实现打印。
    2.4 IEWebBrowser+Javascript
    这实际上,是浏览器打印功能菜单的一种程序调用,与打印功能菜单没什么两样。分页的问题仍然存在,只不过,可以让用户不用去点菜单,直接在网页中的一个按钮,或一个链接里面调用罢了。
    2.5 利用word或excel来实现
    先将需要打印的数据导入到word或者excel中,再利用word或者excel的打印功能来实现web打印。
    2.6 使用第三方控件
    这种方案就是下载一个控件,票据的数据不再以html方式呈现,而是呈现在ActiveX中。这种方案的优点是打印的精确度高,分页的可控性好,但缺点也是很明显的,嵌入ActiveX控件破坏了web应用的整体html风格,且这样的控件比较大(一般超过1M),下载颇费时间)。市场上的非java类报表产品,一般都采用这种方案。
    3 Web打印控件介绍
    3.1 ScriptX
    ScriptX是一个叫MeadCo的国外公司的产品,它分为基础版(免费)和高级版(收费),基础版可以对 页眉,页脚,页边距,纸张方向进行设置。高级版有一些额外的功能,由于是收费的,需要付费以后才能用到你系统中.
    3.2 DLPrinter
    DLPrinter打印控件完全免费,界面大方、使用简单、但无签名,支持打印预览、直接打印,可设置页眉、页脚、页边距、打印份数、纸张大小等信息。遗憾的是作者不知道是什么原因,从2007年至今没的更新。 
    作者博客:http://www.cnblogs.com/Yahong111/ 
    下载地址:http://files.cnblogs.com/panshenglu/DLPrinter.rar
    3.3 墙外打印控件
    墙外打印控件(QWPrint)是一款小巧的打印辅助软件,能够帮助众多制作B/S类程序的程序员更加灵活的控制客户端打印。 
    功能特点: 
    1) 小巧轻便,客户端在第一次使用时只要下载一个ActiveX控件即可使用。 
    2) 控制多种打印设置。程序员可以通过控件进行多项设置,包括设置打纸的页边距,页眉页脚,纸张大小等参数。 
    3) 精确控制打印。可以方便实现web下的套打操作。 
    作者博客:http://www.xwangye.com/ 
    下载地址:http://files.cnblogs.com/panshenglu/墙外打印控件.rar
    3.4 Lodop
    对于这个打印控件,用一个词来形容:强大!不仅调用方便,而且功能比你想像中要强大得多。 
    更多介绍大家到作者博客详细了解。 
    作者博客:http://blog.sina.com.cn/caoyanqingwebsite/ 
    下载地址:http://files.cnblogs.com/panshenglu/lodop4.0.zip
    3.5 WebPrint(商业)
    webprint使用简单,灵活.能满足绝大多数页面打印的需要.它内含一个在vc7.0上开发的ATL小控件(只有74k),这个小控件主要实现对IE浏览器中文档打印格式的控制,可以定制打印纸型,纸张来源,打印方向,设置表头,表尾,表格,表格列宽,打印预览,分页,缩放等等用户经常关心的属性。 webprint使用户通过脚本可以控制自定义纸张,打印方向,页边距等等属性达到定制打印的目的,这些定制属性的设置不会改变IE浏览器的默认打印机属性。也可以通过服务器端的页面调用WebPrint生成客户端的页面达到设置打印参数的目的。
    技术特点:
    1) 基于表格的页面打印解决方案
    2) 采用了VC7.0开发的设置打印参数的小组件(仅75K),实现打印纸张,方向,页边距等等的自定义。
    3) 采用了DHTML, 不仅实现分页,换页重新打印标题,表头表尾等等,而且还实现了精确的放缩功能。
    4) 因为将数据接口层定在标准的HTML元素这一层,所以适合所有在IE下运行的互联网程序,包括ASP JSP PHP和VS.net等等..
    5) 使用简单方便,需要学习的东西很少.
    6) 无须为webprint重新组织要打印的数据和样式,直接将显示的页面传入webprint即可实现数据和样式的打印.
    7) 支持横向分页,分页时固定列重复打印.
    8) 可以动态改变每页的标题.
    9) 支持批打印,即一次打印多个打印作业.
    10) 在同一个页面上可以打印多个报表.
    11) 支持大数据量的打印.
    12) 可以设置打印到某些行时强行分页.
    13) 支持图片的打印.
    14) 可以导出为Excel文件。
    4 Web页面打印应用实例
    4.1 Javascript自带函数
    <a href="javascript:window.print();">打印</a>
    4.2 IEWebBrowser组件
    详细介绍参考:
    http://support.microsoft.com/default.aspx?scid=kb%3BEN-US%3BQ267240#top 
    http://support.microsoft.com/kb/q247671/#appliesto
    <OBJECT classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=0 id=WebBrowser width=0></OBJECT> 
    <input name=Button onClick=document.all.WebBrowser.ExecWB(1,1) type=button value=打开>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(2,1) type=button value=关闭所有>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(4,1) type=button value=另存为> 
    <input name=Button onClick=document.all.WebBrowser.ExecWB(6,1) type=button value=打印>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(6,6) type=button value=直接打印>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(7,1) type=button value=打印预览>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(8,1) type=button value=页面设置>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(10,1) type=button value=属性>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(17,1) type=button value=全选>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(22,1) type=button value=刷新>
    <input name=Button onClick=document.all.WebBrowser.ExecWB(45,1) type=button value=关闭>
    4.3 通过Excel实现页面打印
    将网页中数据导入excel中的方法有很多,这里先介绍一种,利用ActiveX控件的方式,即 Excel.Application, 这个控件是MS为excel提供的编程接口,在很多种编程语言种都可以通过该接口来操纵excel表格。
    下面用javascript脚本来实现一个简单的例子。
    < script language="javascript">
    function ExcelPrint(){
    var excelApp;//存放Excel对象
    var excelBook;//存放Excel工件簿文件
    var excelSheet;//存放Excel活动工作表
    try{
    excelApp = new ActiveXObject("Excel. Application");//创建Excel对象}
    catch(e){
    alert("请启用ActiveX控件设置!");
    return;}
    excelBook = excelApp.Workbooks.Add();//创建Excel工作簿文件
    excelSheet = excelBook.ActiveSheet;//激活Excel工作表
    var rowLen = printTable.rows.length;//table对象的行数
    for (var i=0;i< rowLen;i++){
    var colLen = printTable.rows(i).cells.length;//table对象的列数
    for (var j=0;j< colLen;j++)//为Excel表的单元格赋值
    excelSheet.Cells(i+1,j+1).value = printTable.rows(i).cells(j).innerText;} //将表格中的每个单元格的innerText导入到excel的单元格中
    excelApp.Visible = true;//设置Excel对象可见}
    excelSheet.PrintOut(); //打印工作表
    excelBook.Close(true); //关闭文档
    excelApp.Quit(); //结束excel对象
    excelApp=null; //释放excel对象
    < /script> 

    注意:运行该程序的前提是 IE要允许对没有标记为安全的Activex控件进行初始化和脚本运行。设置方法如下:
    打开控制面板→Internet选项→安全性→自定义级别→对没有标记为安全的ActiveX控件进行初始化和脚本运行→选中启用,这样我们的程序就可以 运行了。如果没有启用该ActiveX控件设置,那么程序在执行创建Excel对象时会抛出一个异常,这时可以通过catch()语句来捕获这个异常,并 且做出相应的处理。 运行该程序必须客户端安装了MS EXCEL,否则Activex驱动不了。
    4.4 使用ScriptX控件
    1. 下载ScriptX.cab控件 
    官网地址:http://www.meadroid.com/scriptx/index.asp 
    2. 使用object元素,修改codebase,classid的值,调用控件ScriptX.cab
    <OBJECT id="factory" style="DISPLAY: none" codeBase="${rootUrl}js/smsx.cab#VVersion=6,3,435,20" classid="clsid:1663ed61-23eb-11d2-b92f-008048fdd814" viewastext></OBJECT>
    这段代码用来加载cab文件,clsid和codebase必须要和你下载的cab中的信息对应,否则组件会加载错误,这两项其实不难找,只要你用winrar打开你下载的cab文件,然后找到扩展名是.inf的文件,然后打开之,就能看到了。 
    3. 调用控件JS脚本
    function setPrintBase(headerText,footerText,rootUrl) {
    // -- advanced features  ,未曾使用过,有待确认。
    //factory.printing.SetMarginMeasure(2); // measure margins in inches
    //factory.SetPageRange(false, 1, 3);// need pages from 1 to 3
    //factory.printing.printer = "HP DeskJet 870C";
    //factory.printing.copies = 2;
    //factory.printing.collate = true;
    //factory.printing.paperSize = "A4";
    //factory.printing.paperSource = "Manual feed"
    var header = (headerText==null||headerText=="")?'默认页眉':headerText;
    var footer = (footerText==null||footerText=="")?'默认页角':footerText;
    factory.printing.header = "&b"+header+"&b" ;
    factory.printing.footer = "&b"+footer;
    factory.printing.portrait = true;
    factory.printing.leftMargin =10.00;
    factory.printing.topMargin =10.00;
    factory.printing.rightMargin =10.00;
    factory.printing.bottomMargin =10.00;
    }
    4. 应用实例
    <html>
    <head>
    <meta http-equiv="imagetoolbar" content="no">
    <script language="javascript" src="print.js"></script>
    <style media="print">
    .Noprint {DISPLAY: none;}
    </style>
    <title>打印测试</title>
    </head>
    <OBJECT id="factory" style="DISPLAY: none" codeBase="smsx.cab#VVersion=6,3,435,20" classid="clsid:1663ed61-23eb-11d2-b92f-008048fdd814" viewastext></OBJECT>

    <script defer>
    function window.onload() { 
    setPrintBase('页眉','页脚');
    }
    </script>
    <body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0" marginwidth="0" marginheight="0">
    <center class="Noprint">
    <input type=button value="打印" onclick="factory.printing.Print(true)"> 
    <input type=button value="页面设置" onclick="factory.printing.PageSetup()"> 
    <input type=button value="打印预览" onclick="factory.printing.Preview()"> 
    <input type="button" value="关闭" onclick="window.close();">
    </center>
    <center>
    <table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tr><td align="center"><b>内容</b></td></tr>
    </table>
    </center>
    </body>
    </html>

    5 Web页面打印技巧
    5.1 隐藏打印的Web元素
    <html><head><title>web打印去掉页眉页脚,以及不想打印出的页面元素</title>
    <meta http-equiv=content-type content="text/html; charset=gb2312">
    <script language=javascript>
    function printpr() {//预览函数
    document.all("qingkongyema").click();//打印之前去掉页眉,页脚
    document.all("dayindiv").style.display="none"; //打印之前先隐藏不想打印输出的元素(此例中隐藏“打印”和“打印预览”两个按钮)
    var olecmdid = 7;
    var prompt = 1; 
    var webbrowser = '<object id="webbrowser1" width=0 height=0 classid="clsid:8856f961-340a-11d0-a96b-00c04fd705a2"></object>';
    document.body.insertadjacenthtml('beforeend', webbrowser); 
    webbrowser1.execwb(olecmdid, prompt);
    webbrowser1.outerhtml = "";
    document.all("dayindiv").style.display="";//打印之后将该元素显示出来(显示出“打印”和“打印预览”两个按钮,方便别人下次打印)

    function printture() { //打印函数
    document.all('qingkongyema').click();//同上
    document.all("dayindiv").style.display="none";//同上
    window.print();
    document.all("dayindiv").style.display="";
    }
    function dopage(){
    layloading.style.display = "none";//同上
    }
    </script>
    <script language="vbscript">
    dim hkey_root,hkey_path,hkey_key
    hkey_root="hkey_current_user"
    hkey_path="softwaremicrosoftinternet explorerpagesetup"
    '//设置网页打印的页眉页脚为空
    function pagesetup_null()
    on error resume next
    set regwsh = createobject("wscript.shell")
    hkey_key="header" 
    regwsh.regwrite hkey_root+hkey_path+hkey_key,""
    hkey_key="footer"
    regwsh.regwrite hkey_root+hkey_path+hkey_key,""
    end function
    '//设置网页打印的页眉页脚为默认值
    function pagesetup_default()
    on error resume next
    set regwsh = createobject("wscript.shell")
    hkey_key="header" 
    regwsh.regwrite hkey_root+hkey_path+hkey_key,"&w&b页码,&p/&p"
    hkey_key="footer"
    regwsh.regwrite hkey_root+hkey_path+hkey_key,"&u&b&d"
    end function
    </script>
    </head>
    <body background="images/background_01.gif" leftmargin=0 
    topmargin=0 rightmargin=0 bottommargin=0 style="background-position: center 50%">
    <div align=center>
    你希望打印的内容..........
    </div>
    <div align="center" id="dayindiv" name="dayindiv"><input type="button" class="tab" value="打印" onclick="printture();"> 
    <input type="button" class="tab" value="打印预览" onclick="printpr();">
    <input type="hidden" name="qingkongyema" id="qingkongyema" class="tab" value="清空页码" onclick="pagesetup_null()"> 
    <input type="hidden" class="tab" value="恢复页码" onclick="pagesetup_default()">
    </div>
    </body>
    </html>
    5.2 实现简单的页面局部打印
    5.2.1 Javascript实现
    function preview(oper)
    ......{
    if (oper < 10)......{
    bdhtml=window.document.body.innerHTML;//获取当前页的html代码
    sprnstr="<!--startprint"+oper+"-->";//设置打印开始区域
    eprnstr="<!--endprint"+oper+"-->";//设置打印结束区域
    prnhtml=bdhtml.substring(bdhtml.indexOf(sprnstr)+18); //从开始代码向后取html

    prnhtml=prnhtml.substring(0,prnhtml.indexOf(eprnstr));//从结束代码向前取html
    window.document.body.innerHTML=prnhtml;
    window.print();
    window.document.body.innerHTML=bdhtml;
    } else ......{
    window.print();
    }
    }
    使用很简单 将页面内要打印的内容加入中间<!--startprint1-->XXXXX<!--endprint1-->
    再加个打印按纽 onclick=preview(1)
    5.2.2 WebBrowser实现

    1. WebBrowser控件 
      <object ID='WebBrowser' WIDTH=0 HEIGHT=0 CLASSID='CLSID:8856F961-340A-11D0-A96B-00C04FD705A2'></object> 
    2. WebBrowder控件的方法 
    //打印 
    WebBrowser1.ExecWB(6,1); 
    //打印设置 
    WebBrowser1.ExecWB(8,1); 
    //打印预览 
    WebBrowser1.ExecWB(7,1); 
    关于这个组件还有其他的用法,列举如下: 
    WebBrowser.ExecWB(1,1) 打开 
    Web.ExecWB(2,1) 关闭现在所有的IE窗口,并打开一个新窗口 
    Web.ExecWB(4,1) 保存网页 
    Web.ExecWB(6,1) 打印 
    Web.ExecWB(7,1) 打印预览 
    Web.ExecWB(8,1) 打印页面设置 
    Web.ExecWB(10,1) 查看页面属性 
    Web.ExecWB(15,1) 好像是撤销,有待确认 
    Web.ExecWB(17,1) 全选 
    Web.ExecWB(22,1) 刷新 
    Web.ExecWB(45,1) 关闭窗体无提示 
    但是打印是会把整个页面都打印出来的,页面里面有什么东西就打印出来,我们有时候只需要打印数据表格,这时我们就要写一个样式了:把不想打印的部份隐藏起来:
    样式内容:
    <style type="text/css" media=print>
    .noprint......{display : none }
    </style>
    然后使用样式就可以:
    <p class="noprint">不需要打印的地方</p>
    代码如下:
    <script language="javascript"> 
    function printsetup()......{ 
    // 打印页面设置 
    wb.execwb(8,1); 

    function printpreview()......{ 
    // 打印页面预览 
    wb.execwb(7,1); 

    function printit() 
    ......{ 
    if (confirm('确定打印吗?')) ......{ 
    wb.execwb(6,6) 


    </script> 
    <OBJECT classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2" height=0 id=wb name=wb width=0></OBJECT> 
    <input type=button name=button_print value="打印" class="noprint" onclick="javascript:printit()"> 
    <input type=button name=button_setup value="打印页面设置" class="noprint" onclick="javascript:printsetup();"> 
    <input type=button name=button_show value="打印预览" class="noprint" onclick="javascript:printpreview();">
    5.3 禁止出现页眉页脚
    <HTML><HEAD>
    <script language="JavaScript">
    var hkey_root,hkey_path,hkey_key
    hkey_root="HKEY_CURRENT_USER"
    hkey_path="\Software\Microsoft\Internet Explorer\PageSetup\"
    //设置网页打印的页眉页脚为空
    function pagesetup_null()
    {
    try{
    var RegWsh = new ActiveXObject("WScript.Shell")
    hkey_key="header" 
    RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,"")
    hkey_key="footer"
    RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,"")
    }catch(e){}
    }
    //设置网页打印的页眉页脚为默认值
    function pagesetup_default()
    {
    try{
    var RegWsh = new ActiveXObject("WScript.Shell")
    hkey_key="header" 
    RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,"&w&b页码,&p/&P")
    hkey_key="footer"
    RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,"&u&b&d")
    }catch(e){}
    }
    </script>
    </HEAD>

    <BODY><br/><br/><br/><br/><br/><br/><p align=center>
    <input type="button" value="清空页码" onclick=pagesetup_null()>
    <input type="button" value="恢复页码" onclick=pagesetup_default()><br/>
    </p></BODY></HTML>

  • 相关阅读:
    有36辆自动赛车和6条跑道,没有计时器的前提下,最少用几次比赛可以筛选出最快的三辆赛车?----腾讯2016研发工程师在线模拟笔试题
    10G个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可
    计算机网络总结(二)
    计算机网络总结(一)
    最小编辑距离
    寻找两个有序数组的中位数
    Linux下几款C++程序中的内存泄露检查工具
    DDIA
    推荐引擎
    Innodb中的事务隔离级别和锁的关系
  • 原文地址:https://www.cnblogs.com/moonvan/p/3419280.html
Copyright © 2011-2022 走看看