zoukankan      html  css  js  c++  java
  • Web页面打印技术读后感

    最近做了很多打印方面的技术,感觉都是不理想,下面介绍网上找到的,应用到自己的项目的重点技术问题,以备日后自己学习与收藏以及分享给大家共享。lifuyun

    一.概述
      对基于B/S架构的应用程序而言,客户端的页面打印一直是比较头疼的问题,简单的做法是:1.使用IE的打印功能;2.使用水晶报表。但以上两种办法,都有很大的局限性,很难实现特殊要求的排版和精确的定位,所以不能满足一些特殊客户的BT要求。为此,本人总结了自己在使用Web打印上的一点经验,和大家分享。
      本文涉及以下技术:javascript、ActiveX、ASP.NET、GDI+。

    二.基本架构
      首先,我们不能使用IE的打印功能,必须自己设计‘打印’按钮。很多人习惯将‘打印’按钮放在要打印的页面上,打印时为了不把这个按钮打印出来,采用办法如下:1.打印前隐藏按钮;2.打印;3.显示按钮。
    我觉得这样比较麻烦,所以我采用框架。一共有三个页面:
    1.main.htm :框架页面,上面是打印按钮,下面是要显示的页面。
    2.header.htm :标题栏,至少包含一个打印按钮。
    3.report.aspx :要打印的页面,由用户生成。

    //main.htm
    <html>
     <head>
      <title></title> 
     </head>
      <frameset rows="10%,90%" frameborder="0" border="0" frameSpacing="0">
      <frame id="header" name="header" src="Header.htm" noresize scrolling="no">
      <frame id="report" name="report" src="Report.aspx" noresize scrolling="auto">
     </frameset>
    </html>

    //header.htm
    <html>
     <head> 
      <script id=clientEventHandlersJS language=javascript>
      <!--
      function btnPrint_onclick()
      {  
         parent.report.focus();
         parent.report.print(); 
      }
      //-->
      </script>
     </head>
     <body>
      <INPUT id="btnPrint" type="button" value="Print" name="Print" onclick="return btnPrint_onclick()"> 
     </body>
    </html>

      这样,在点击‘打印’按钮时,将直接打印report.aspx页面的内容,既简单又直观。

    三.打印
     要完全控制打印,就必须由程序设定页眉、页脚、页边距。每个客户端的IE设置都不尽相同,你可以要求你的客户修改他们的打印设置为你指定的值,显然这不现实。所以正确的做法是:
    1.备份客户打印页面设置;
    2.设置页眉页脚上下左右边距为自己需要的值;
    3.打印;
    4.恢复原来的打印页面设置。

     这里用到一个叫ScriptX的控件。你需要下载一个文件:smsx.cab,下载地址:http://www.meadroid.com/scriptx/sxdownload.asp。这个地址并不能保证长期有效,你可以在搜索引擎上搜索‘ScriptX’以获得更多相关信息。

    在“header.htm”中增加该控件的引用:
    <OBJECT id="factory" style="DISPLAY: none" codeBase="http://localhost/WebApplication1/smsx.cab#VVersion=6,3,434,12"
     classid="clsid:1663ed61-23eb-11d2-b92f-008048fdd814" viewastext>
    </OBJECT>
    注意CodeBase指向你的实际存放文件的位置,在客户端第一次浏览该页面时,将下载并安装该控件,请确定客户端的安全设置允许安装控件。
    那么此时 header.htm 的内容如下。

    //header.htm
    <html>
    <head>
     <script id="clientEventHandlersJS" language="javascript">
     <!--
     function btnPrint_onclick()
     {
      //备份客户打印机设置
       var h = factory.printing.header;
       var f = factory.printing.footer;
       var t = factory.printing.topMargin;
       var b = factory.printing.bottomMargin;
       var l = factory.printing.leftMargin;
       var r = factory.printing.rightMargin;
     
       //设置页眉页脚上下左右边距 
       factory.printing.header = "";
        factory.printing.footer = "";
        factory.printing.topMargin="0";
       factory.printing.bottomMargin="0";
       factory.printing.leftMargin="0";
       factory.printing.rightMargin="0";
     
       //打印
       parent.report.focus();
       parent.report.print()
     
       //恢复原来的打印设置
       factory.printing.header = h;
       factory.printing.footer = f;
        factory.printing.topMargin=t;
       factory.printing.bottomMargin=b;
       factory.printing.leftMargin=l;
       factory.printing.rightMargin=r;
     }
     //-->
     </script>
     
     <OBJECT id="factory" style="DISPLAY: none" codeBase="http://localhost/WebApplication1/smsx.cab#VVersion=6,3,434,12"
      classid="clsid:1663ed61-23eb-11d2-b92f-008048fdd814" viewastext>
     </OBJECT>
    </head>
    <body bgColor="#9999cc">
     <INPUT id="btnPrint" type="button" value="Print" name="Print" onclick="return btnPrint_onclick()">  
    </body>
    </html>

      此时,不管客户端IE设置如何,都能正确打印页面,打印内容将完全取决于页面:report.aspx。

    四.动态页面生成
    1. 如果你的页面是静态页面,或者页面元素为固定数量,那就非常简单了。只要调整好各个元素位置就行了,绝对所见即所得。要注意的是一个A4纸的大小为21cm×29.7cm,对应象素大约为 794×1123 (系统分辨率96DPI) 。

    2.如果你要生成一些图表,可以使用GDI+,你自己绘制的图片绝对能满足客户需求。下面给一个例子,我在页面放一个Label,一个Image。Image动态生成,调整其位置使其打印时出现在第二页的左上角。


     1public class Report : System.Web.UI.Page
     2 {
     3  protected System.Web.UI.WebControls.Image Image1;
     4  protected System.Web.UI.WebControls.Label Label1;
     5
     6  web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
     7  override protected void OnInit(EventArgs e)
     8  {  
     9   InitializeComponent();
    10   base.OnInit(e);
    11  }
    12  private void InitializeComponent()
    13  {   
    14   this.Load += new System.EventHandler(this.Page_Load);
    15  }
    16  #endregion
    17
    18  private void Page_Load(object sender, System.EventArgs e)
    19  {  
    20   if(!Page.IsPostBack)
    21   {
    22    InitImage();
    23   }
    24  }
    25
    26  private void InitImage()
    27  {
    28   Bitmap bmp = new Bitmap(800,1120);
    29   Graphics g =  Graphics.FromImage(bmp);
    30
    31   g.FillRectangle(Brushes.Gray,0,0,800,1120);
    32
    33   g.FillRectangle(Brushes.RoyalBlue,0,0,100,600);
    34   g.FillRectangle(Brushes.Aqua,600,0,100,600);
    35   g.FillRectangle(Brushes.Coral,700,0,100,600);
    36
    37   g.FillRectangle(Brushes.YellowGreen,0,800,800,100);
    38   g.FillRectangle(Brushes.Beige,0,900,800,100);
    39   g.FillRectangle(Brushes.SkyBlue,0,1000,800,100);
    40   g.FillRectangle(Brushes.Tomato,0,1100,800,20);
    41
    42   string filename = Server.MapPath("TempImages\\img1.jpg");  
    43
    44   bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
    45
    46   this.Label1.Text = filename;
    47   this.Image1.ImageUrl = filename;
    48   this.Image1.Attributes["style"]="POSITION: absolute; LEFT: 0cm;  TOP: 29.7cm"; //定位
    49  } 
    50 }
    51
    52

    注意:要保证存放图片的目录,有写权限。

    3.以上技术只适合于页面元素为固定数量的情况,对于页面内容大小不定的情况,例如,要打印一份人员信息的清单,人员数量为1~1000不等,每页显示20条记录,要有规定的页眉、页脚,此时该如何处理。
      思路:ASP.NET页面都有一个基类System.Web.UI.Page,该类有一个保护方法叫void Render(HtmlTextWriter writer),就是通过这个方法,ASP.NET在后台把WEB服务器端控件的属性转换成HTML代码,并发送到客户端供浏览器显示。我们的办法就是“劫持”该方法,完全手工生成所需页面标记代码。
    先看一个例子:
     public class FrmRYInfo : System.Web.UI.Page
     {
      private void Page_Load(object sender, System.EventArgs e)
      {  
      }
      protected override void Render(HtmlTextWriter writer)
      {
       writer.Write("<HTML>");
       writer.Write("<body>");
       writer.Write("<h1>Hello,world!</h1>"); 
       writer.Write("</body>");
       writer.Write("</html>");
      }
     }
      编译并运行以上程序,可以看到一行一号字体的"Hello,world!",查看页面源文件,内容如下:
     <HTML><body><h1>Hello,world!</h1></body></html>
      对照上面代码,应该非常好理解,下面我们就做一个实际的例子,将信息从数据库读出,显示在页面上,每页显示15条记录。


     protected override void Render(HtmlTextWriter writer)
      {
       writer.Write("<HTML>");
       writer.Write("<body>"); 

       DataTable tabRY = GetCustomerInfo(); //读取数据库

       int Lines = 15;    //每页行数
       int Count = tabRY.Rows.Count;
       int TotalPage = Count/Lines + (Count%Lines==0?0:1);

       for(int CurrentPage =0; CurrentPage<TotalPage; CurrentPage++)
       {
        int StartRow = CurrentPage * Lines;
        int EndRow = StartRow + Lines;
        if(EndRow > Count) EndRow = Count;

        ProcessCurrentPage(writer,tabRY,StartRow,EndRow,CurrentPage,TotalPage);
       }
     
       writer.Write("</body>");
       writer.Write("</html>");
      }

      private void ProcessCurrentPage(HtmlTextWriter writer, DataTable tabRY, int StartRow, int EndRow, int

    CurrentPage, int TotalPage)
      {
       if(CurrentPage != 0)
       {
        writer.Write("<p  style=page-break-before:always></p>");
                  }
      
       writer.Write("<table  width=630 height=417 border=0>");
       writer.Write(" <tr>");
       writer.Write("  <td width=624 height=47><div align=center  style=font-size:24px>人员信息汇总

    表</div></td>");
       writer.Write("  </tr>");
       writer.Write("  <tr>");
       writer.Write("  <td height=222>");

       writer.Write("   <table width=623  border=1 cellpadding=0 cellspacing=0>");
       writer.Write("   <tr>");
       writer.Write("    <td width=134><div align=center>姓名</div></td>");
       writer.Write("    <td width=134><div align=center>编号</div></td>");
       writer.Write("    <td width=134><div align=center>电话</div></td>");
       writer.Write("    <td width=134><div align=center>小灵通</div></td>");        
       writer.Write("   </tr>");

      for(int i=StartRow; i<EndRow; i++)
      {
       DataRow row = tabRY.Rows[i];
       string XM = row["MC"].ToString();
       string BH = row["BH"].ToString();
       string DH = row["LXDH"].ToString();if(DH.Length==0)DH="-";
       string XLT =  row["XLT"].ToString();

       writer.Write("   <tr>");
       writer.Write("    <td width=134><div align=center>" + XM + "</div></td>");
       writer.Write("    <td width=134><div align=center>" + BH + "</div></td>");
       writer.Write("    <td width=134><div align=center>" + DH + "</div></td>");
       writer.Write("    <td width=134><div align=center>" + XLT + "</div></td>");    

       
       writer.Write("   </tr>");
      }

       writer.Write("   </table>");

       writer.Write("  </td>");
       writer.Write("  </tr>");
       writer.Write("  <tr>");
       writer.Write("  <td height=37><div align=right>第" + (CurrentPage+1).ToString() +"页,共" +

    TotalPage.ToString() + "页</div></td>");
       writer.Write("  </tr>");
       writer.Write("</table>");
      }

    以上的代码确实很好用,自己经过改造后的确可以达到自己需要的效果。感谢网络资源,lifuyun-云中深海.

  • 相关阅读:
    cpu核数和逻辑个数的区别_CPU逻辑核心数和物理核心数
    linux查看CPU数
    Java读取excel中日期格式结果为数字44326天
    Java实现读取excel中的数据及图片
    jmeter设置全局变量,获取登录token,实现两个线程组参数公用
    CPU使用率
    快照版本和发布版本区别
    jmeter与postman请求结果返回不一致
    接口认证方式:Bearer Token
    jmeter 中报java.lang.OutOfMemoryError: Java heap space
  • 原文地址:https://www.cnblogs.com/lifuyun/p/lifuyun09112005.html
Copyright © 2011-2022 走看看