一.概述
  对基于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" οnclick="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" οnclick="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>");
  }

感觉又回到了用记事本做网页的年代,手工生成HTML代码,是不是真正叫“随心所欲”。
几点说明:
(1)在每一页(除了第一页)的头部加入 writer.Write("<p  style=page-break-before:always></p>"); 目的是控制在打印时,打印机在此换页。这里通过强制打印机换页来实现页面的布局,与上面的绝对定位的办法不同。该标记只影响打印,不影响显示。
(2)用记事本做网页绝对很痛苦,而且HTML标记也很不好用,我的办法是:用Dreamweaver生成需要的页面,再参照其HTML代码进行编程。
(3)尽量使用HtmlTextWriter类提供的一些其它方法如WriteBeginTag等取代Write方法,这样可以提高页面在客户端的兼容性。同时在每个标记后加入writer.WriteLine();进行换行,以便于调试。

转载于:https://www.cnblogs.com/Aioria0622/archive/2007/12/03/981434.html

随心所欲的Web页面打印技术相关推荐

  1. 转自博客园:随心所欲的Web页面打印技术

    原文地址:http://www.cnblogs.com/seabluescn/archive/2006/11/23/569945.html 一.概述   对基于B/S架构的应用程序而言,客户端的页面打 ...

  2. 随心所欲的Web页面打印技术 20(转载)

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

  3. Web系统页面打印技术实现与分析

    1 Web页面打印概述 应用WEB化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于WEB的应用,客户端的规则很简单,容易学习,容易维护,容易发布.在WEB系统中,打印的确是个烦人的问 ...

  4. C# Web页面打印网页

    C# Web页面打印网页 <style media=print type="text/css">       .noprint{display:none}   < ...

  5. Web页面打印及GridView导出到Excel

    打印Web页面 在头部<head>加入 打印事件 <script   language=javascript>      function   doPrint()   {    ...

  6. 关于ASP.NET页面打印技术的总结

    网络打印概述 • B/S结构导致了Web应用程序中打印的特殊性. • 程序运行在浏览器中,打印机在本地,而文件确可能在服务器上,导致了打印控制不是很灵活. • 格式如何控制和定制等,是我们开发中可能会 ...

  7. 介绍一种Web上打印技术

    一.    介绍ScriptX控件 对于B/S架构的项目中,Web打印最是让程序员头痛的技术,在这次项目中运用了第三方控件ScriptX解决了此技术包括各种汇总表,详细清单等等,但最大弊端就是打印的格 ...

  8. ASP.NET页面打印技术的总结

    网络打印概述 ◆B/S结构导致了Web应用程序中打印的特殊性. ◆程序运行在浏览器中,打印机在本地,而文件却可能在服务器上,导致了打印控制不是很灵活. ◆格式如何控制和定制等,是我们开发中可能会面对的 ...

  9. web页面打印 用Css 打印指定div 指定位置分页

    用Css指定打印标签 有两个地方需要注意: 1.CSS的@media print {}里面添加不需要打印(display:none) 和 要打印(display:block) 的DIV: 2.如果页面 ...

最新文章

  1. 十大经典排序算法Python版实现(附动图演示)
  2. 数据库名、实例名、数据库域名、全局数据库名、服务名,
  3. 【NLP】听李宏毅点评GPT-3:来自猎人暗黑大陆的模型
  4. 说普通话时舌头卷不起来是一种什么体验?| 今日最佳
  5. QT5_PYQT导入自己的图片
  6. linux 触摸屏在dev的那个目录下,各硬件设备在Linux中的文件名
  7. MATLAB切比雪夫带通滤波器
  8. Spring系列技术实战(项目搭建、知识点总结)
  9. matlab指派问题求法,matlab求解指派问题
  10. arcgis 将2000球面坐标转换成平面坐标
  11. 熊猫阿波的故事 2201
  12. 前端使用xlsx-js-style导出Excel文件并修饰单元格样式
  13. 软件测试应该何时介入项目?
  14. Python 给图片加文字,加图片水印
  15. 图像处理冷知识——dpi和ppi
  16. ARM各版本架构区别,各架构的系列芯片。
  17. 史上最全Maven教程(二)
  18. 向毕业妥协系列之深度学习笔记(三)DL的实用层面(上)
  19. synaptic No protocol specified issue
  20. 什么是网络爬虫?它是如何工作的以及如何自动抓取

热门文章

  1. 编程之美2.13子数组的最大乘积
  2. ubuntu每次登陆都用root账号登陆
  3. String类的使用 Part2
  4. 邮件群发工具的编写(二)数据的保存
  5. HTML与CSS布局技巧总结
  6. Niginx 集群负载均衡策略
  7. offset系列,client系列,scroll系列回顾
  8. node.js HelloWord
  9. Java - I/O
  10. $* $@ $# $? $$ $! $0 $_