1. 程式人生 > >Web系統頁面列印技術實現與分析

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="\software\microsoft\internet explorer\pagesetup"
'//設定網頁列印的頁首頁尾為空
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>