设计方案的简单实现网址:http://www.lc-simple.com/PrintTest/
Web打印控件的工作的原理如下:
服务端的代码是开源的,提供的语言版本有:.NET,Java,PHP。使用控件时,需要引用服务端的一些类和函数,把打印数据、报表模板文件及打印设置产生为一个JSON临时文件,并把此URL传给网页,通过网页去调用客户端打印软件。
服务端代码主要分为4个部分:网页、和网页相配套的服务端代码、打印类、数据库操作类。服务端代码的核心在于打印类,其他3个只是作为完整的示例应用必不可少的支持(为了示例的简单易懂,我对这3个部分的配置和代码也是尽可能的简单化,尽可能的少用框架)。在实际的开发中,您只需要引用打印类,然后其它根据项目要求去做就可以了。
我平时工作一般是用.NET,对于Java主要是用于Android系统的开发,对于PHP用得比较少。对于服务端的代码,您可以根据自己的需求,进行自行开发和修改。欢迎各位同行一起来交流,大家共同进步。
一、网页端的相关代码
<script src="./js/jquery-1.10.1.min.js" type="text/javascript">script>
<iframe id="ifrm" src="" width="0" height="0">iframe>
<script type="text/javascript">
var strPrintData = '<%=strPrintData%>';
if( strPrintData != '' ) {
$("#ifrm")[0].src = "ChuLinPrint:<%=strPrintData%>";
}
script>
其中<%=strPrintData%>是引用服务端的变量,即服务端所产生的临时文件的URL,这个实例是.NET的写法,Java和PHP稍不一样。
把URL作为参数传递给客户端打印软件,并调用客户端打印软件进行操作,其它的代码您可以根据自己的要求去改写。
二、PrintFunction类文件设计
此源文件在实际开发中必须添加至开发项目中,此源文件一般提供了以下4个静态函数以供开发调用。各语言的写法稍有差异,但功能是一样的。下面以C#的格式简单说明一下这4个函数。
此函数把List类的实例转化为XML字符串,把报表的数据转换为XML字符串。这个函数一般不用去做任何修改,如果数据类型不够用,也请按照现有源代码的严格格式去做调整,否则就会出错的。List类是我们面向对象开发中最常用的类,此函数提供面向对象开发中的数据处理功能。
此函数把数据表转化为XML字符串,把数据表中的数据和结构转换为XML字符串。对于.NET平台记得在加载数据时,要加载数据表的结构(加上:da.FillSchema(ds, SchemaType.Source);)。若函数中提供的数据类型不够用,可自行按照源代码的格式进行调整。
此函数把报表模板文件和图片文件进行编码,转化为字符串。这个函数一般不用做任何修改。
此函数把字符串转化为base64编码的字符串。这个函数一般不用做任何修改。
三、PrintJson类文件设计
此源文件在实际开发中必须添加至开发项目中,此源文件是服务端代码的核心,提供了打印控件所有功能调用和属性设置。
3.1 JSON第三方类库的引用
系统中采用免费的公开的JSON第三方类库,这些类库都是各语言进行JSON操作最常用的第三方类库。
对于.NET平台需要引用:Newtonsoft.Json.dll,此文件可以在C#示例中的bin文件夹目录下找到。
对于Java需要引用:json.jar,此文件也可以在Java示例中的文件夹中找到。
对于PHP,直接采用的是系统函数:json_encode,无需引用第三方类库。
3.2 类的初始化,传入报表模板文件
PrintJson类初始化时,需要提供2个参数:
类的初始化时,会对打印控件所需要的数据进行初始化值。
3.3 打印控件的注册参数
对应的函数:CheckRegister,需要2个参数:
3.4 报表变量参数的设置
报表变量参数可以由服务器传递数据至报表模板中显示和打印。报表变量一般只传递一个数据值,是数据集的有效补充。
在报表模板的编辑窗口,单击菜单栏上的“报表”,“参数”,如图 ,则打开参数窗口如下图:
单击参数窗口上的 建立参数类别;
单击 建立参数;
单击 可以编辑参数类别和参数的名称。
参数的名称一般由英文字母加数字组成,和编辑语言中的变量一样。
在报表模板的编辑窗口,单击最左边的工具箱上的 ,然后在报表编辑区域再单击一下,就会打开窗口如下:
点击左上角的此图标,打开窗口如下:
在此窗口选择“变量”选项,在第1步定义的报表变量就会在此显示出来,双击变量名称,然后再点“确认”,就可以使用此报表变量了。
服务端的函数:AddPrintParam,需要2个参数:
报表变量的参数名称:这个参数名称就是在第1步的报表模板编辑时所设置的参数名称,这个参数名称区分大小写,必须和报表模板文件中的参数名称一模一样。
报表变量的参数值:就是此参数的值,为了简便起见,报表变量的参数值都为字符串,其它类型请先转化为字符串。
3.5 检测打印机控件是否安装
如果您的开发项目的客户端电脑由您公司或部门的人员直接维护,或在客户使用之前,会对客户进行培训,建议在您的项目中就没有必要对打印控件是否安装进行检测了,这样也省去您不少的代码。
检测打印控件是否安装的解决思路由以下3个部分组成:
服务端调用控件之前,判断是否有 Cookie(此Cookie为GuId值,保证唯一性,此Cookie的保存时间为10年以上),若有Cookie则在服务端的数据表中查找,判断是否有记录,若有记录,则表示此电脑已经安装过。 若没有记录,或者没有Cookie,则表示未安装过。若没有Cookie则建立一个Cookie。
调用控件时,把此Cookie值,还有Cookie回传的服务端的URL传给控件。控件在运行时,会自动把此cookie值回传服务器的URL,服务器把此Cookie写入数据表中,并且更新最后一次回调的时间。
网页在调用控件之后,可以再启动一个延时(比如延时3秒)函数,以Ajax去访问服务端的另一个指定的URL,附带参数:Cookie值,服务端去读取数据表的此Cookie的记录,若不存在记录,或最后访问的时间超过了规定时间,则判断为客户机没有安装,提示下载安装。这一步主要是防止客户自己卸装了报表打印控件,而Cookie还正常存在的情况。打印控件安装之后在开始菜单和桌面不会有任何痕迹,但用户可以在“控制面板”中“程序”找到并进行删除,如果您觉得您的客户不会有这么高的专业水平,那么这一步可以忽略不计。
第1步的处理,因为涉及到Cookie,我们必须在网页对应的服务端代码中进行处理。.NET可参照示例中的 Default.aspx.cs文件中的SetCookieAndURL函数;对于Java可参照示例中的PrintTestDemo.java文件中的SetCookieURL函数。对于Cookie值的存储,需要设计一个独立的数据表,此数据表就2个字段:存储的Cookie值、最后访问时间。
第2步的处理,分为2个部分:
第3步的处理,分为2个部分:
3.6 报表图片文件的处理
报表图片文件的处理分为两种情况,一种是单个图片文件,比如在报表的标题处显示公司的LOGO;另一种是报表明细记录中的图片,比如产品明细报表中为每一个产品显示图片。
单个图片文件的处理:
注意:一个报表模板文件可以有多个独立的单个图片文件。
报表明细记录的图片文件的处理:
对于数据表中的图片字段只保存图片的文件名,不保存图片文件的内容,这个也是通用的做法,如果您的图片保存在数据库,建议分离出来作为独立的图片文件存在,因为这样可以大大减轻数据库的压力,也便于有必要的时候可以把图片作为CDN资源,减轻服务器的带宽压力。服务器的图片绝对路径加上数据表的图片字段的值,要可以读取到图片的内容。
3.7 报表预览窗口的设置
报表预览窗口上的按钮栏如下图:
可以通过服务端一系列的函数决定哪一个按钮隐藏不显示出来。
IsHideButtonPrint:报表打印预览窗口隐藏按钮:打印
IsHideButtonLoad:报表打印预览窗口隐藏按钮:打开文件
IsHideButtonSave:报表打印预览窗口隐藏按钮:保存
IsHideButtonExport:报表打印预览窗口隐藏按钮:导出
IsHideButtonZoom:报表打印预览窗口隐藏按钮:放大缩小
IsHideButtonFind:报表打印预览窗口隐藏按钮:查找
IsHideButtonOutline:报表打印预览窗口隐藏按钮:大纲显示
IsHideButtonPageSetup:报表打印预览窗口隐藏按钮:页面设置
IsHideButtonNavigator:报表打印预览窗口隐藏按钮:页面导航
IsHideButtonExportQuick:报表打印预览窗口隐藏按钮:快速导出
3.8 页边距的程序设置
报表的页边距,通常是在报表模板的编辑窗口进行设置。设置的方法,点击左上角的“文件”菜单,再选择“页面设置”,打开窗口如下图:
在此窗口设置好报表的纸张大小、各页边距。请注意这个设置和打印机相关,所设置的页边距若您的打印机不支持,那么实际打印的时候也不会起作用。
服务端所提供的页边距的设置函数主要是用于EPSON针式打印机的细微调整,用EPSON针式打印机打印各种单据时,特别是那种通过滚动方式在打印机后端进纸的,不同的打印机需要去调整各自的边距,此边距可以在打印机上去调整,也可以在服务端通过函数进行调整。提供了4个函数如下:
SetLeftMargin(double dbLeftMargin):设置页面设置的左边距,单位为毫米
SetRightMargin(int dbRightMargin):设置页面设置的右边距,单位为毫米
SetTopMargin(int dbTopMargin):设置页面设置的上边距,单位为毫米
SetBottomMargin(int dbBottomMargin):设置页面设置的下边距,单位为毫米
3.9 在线编辑报表的保存
本软件的DesignReport方法就可以在线编辑报表,若您只是自己在线编辑报表,客户不需要在线编辑和保存报表,那么您可以在报表编辑好之后,单击右上角的“文件”菜单,选择“另存为”,把报表模板文件保存下来,这样就不需要在线保存。
在线保存是指客户在线编辑好报表,在报表编辑窗口,单击 保存图标,报表文件可以自动上传至服务器,并且提示:保存成功。
此操作分为2个部分。
第1个部分是在服务端设置保存的URL,对应的函数:SetPostUrl,参数为服务器保存数据的URL,此URL必须以http://或https://打头,在浏览器能打开。此URL中建议配置相关的参数,如带参数:?FileName=DepsitAmt.fr3,这样以区分不同的文件名,也可以加上其它的参数(比如:UserId等),这些参数在报表保存时都会作为URL的参数完整上传。
第2个部分为此服务端的URL的代码,此代码中接收报表编辑保存的内容,还有第1个部分所设置的URL参数。报表编辑保存的内容是以POST方式上传的,参数名称为:ReportFileValue;上传的报表内容为字符串,需要经过转码才可以保存为报表模板文件。对于.NET可参考示例中的PostSave.aspx.cs文件;对于Java可参考示例中的PostSave.jsp文件。
3.10 在线编辑报表的数据集名称的设置
对于用户在线报表,为了便于用户操作,我们可以把数据集,还有数据集的字段名称设置为中文。对于字段名称设置为中文,对于SQL语句可以用 as 的方式转换为中文。对于数据集的中文设置,本软件提供了以下的函数:
SetDataSetName1(string strDataSetName):设置数据集1的名称为指定名称(可以是中文)
SetDataSetName2(string strDataSetName):设置数据集2的名称为指定名称(可以是中文)
SetDataSetName3(string strDataSetName):设置数据集3的名称为指定名称(可以是中文)
SetDataSetName4(string strDataSetName):设置数据集4的名称为指定名称(可以是中文)
SetDataSetName5(string strDataSetName):设置数据集5的名称为指定名称(可以是中文)
SetDataSetName6(string strDataSetName):设置数据集6的名称为指定名称(可以是中文)
请注意:报表编辑时的数据集名称必须和此函数所设置的数据集名称保持一致,否则报表模板会报错。
3.11 实际打印次数、页面设置的回传服务器的设置
注意:此方法不检测打印机的状态,如遇打印机故障或卡纸,也是同样会上传。对于不预览直接打印的,可以在调用控件后就默认为已经打印1份。
3.12 主从报表的设置
主从报表是指一个主表和一个从表联合进行打印,最常见的如一次性打印多张采购订单,像订单号、供应商名称、订单金额这些就是主表信息,像各订单所对应的采购物品记录就是从表信息。
主从报表模板的设计:如果您不熟悉,可以先看看示例中的主从报表的设计示例。这其中关键的有以下几点:
主从报表数据关联,对应类的函数:MasterOptions(int iMasterDataSeq, string strFieldName, bool bIsNumber),其中第1个参数为主数据集的序号,通常为1;第2个参数为主数据集和从数据集相关联的字段名称,这个字段名称是这2个数据集中都存在的,若相关联需要2个或多个字段,请用SQL语句或类对象中,把这几个字段的值进行转化,转化为一个字段;第3个参数标识此字段的内容是否为数值型。
3.13 直接打印的打印机设置
直接打印时可以设置从用户的哪一部打印机打印出报表,若未设置,则从用户的默认打印机打印出报表。对应类中的函数:SetPrinter,参数为用户已经安装的打印机名称(见“控件面板”、“打印机和传真”),对于网络打印机的名称,注意“\”,要转化为:“\\”;打印机的名称若错误,则还是从默认打印机打印出来。
注意:此设置对于先预览后打印的模式不启作用。
3.14 预览、直接打印、在线编辑、导出PDF的方法
预览:调用控件之后,先显示打印预览的窗口,然后由用户可以查看报表的内容,也可以导出或进行打印。预览的函数名:ShowReport,可以预览List
直接打印:调用控件之后,不进行打印预览,直接从打印机打印出报表的内容;若未设置打印机,则从默认打印机打印出来。直接打印的函数名:PrintReport,此函数的参数和预览完全一样。
在线编辑:调用控件之后,则显示报表编辑的窗口,可以直接进行在线设计报表,若设置了:在线编辑报表的保存,则点击保存时,则可以把设计好的报表模板文件直接上传至服务器;若没有设置,则可以“另存为”的方式保存报表模板文件。在线编辑的函数名:DesignReport,此函数的参数和预览完全一样。
导出PDF:调用控件之后,不进行打印预览,直接把报表内容导出PDF文件。若没有传入导出所保存的文件夹及文件名称,则调用之后,会弹出一个保存文件的对话框,在此对话框选择文件夹和文件名,然后再进行保存。若传入了保存的文件夹及文件名称,则会在用户的电脑先建立此文件夹,并产生文件,若文件已经存在,则覆盖旧文件。导出PDF的函数名称:ExportReportPdf,此函数的参数比预览多一个参数:strExportPdfFileName,就是PDF导出之后所保存的文件夹及文件名称。
3.15 报表模板文件的设计
常见的报表模板的设计也是比较简单的,若您不熟悉,可以上网去查找一下相关报表设计的资料,对于一个程序员来说,学习这个简单的报表设计,很快就可以上手,一般只需1至2个小时就可以学会的。在这里主要是说明一下我在报表模板设计中所增强的几个功能。
A、单击报表右侧工具箱上的 ,并把它拖放到需要打印的位置,这时显示的是一维码,请接着进行下一步
B、修改属性BarcodeType的值为:tBARCODE_QRCODE,这时候显示的样式为二维码
C、二维码的数据设置,若二维码为固定的值,请直接在属性:Data中设置
若二维码的值为动态变化的,请先修改属性:Name 的值,然后单击“事件”页,双击“OnBeforePrint”事件,如下图:
写入一行代码,示例如下:
Qrcode_CashNo.Data :=
其中 Qrcode_CashNo 为所上面所设置的二维码的Name
D、二维码的大小:二维码有严格的规范,不能直接设置大小,但通过属性:Zoom 设置二维码的大小的倍数
E、二维码控件的选择,有时候用鼠标直接点击报表上的二维码没有反应,可以点击左上方的对象查看器的二维码,如下图:
本报表编辑器增加6个中国式报表的按钮,方便解决了中国式报表中线条对齐问题。
这6个按钮分别是缩放宽度最小、缩放宽度最大、缩放高度最小、缩放高度最大、水平首尾相连、垂直首尾相连。
中国式报表的设计方法:拖多个文本对象或数据库字段其报表编辑器,然后选中,单击工具栏上的 按钮,使其加上边框,然后再单击“水平首尾相连”就可以很好的产生水平线条。对于垂直线条,可以选中垂直的报表对象,然后再单击左对齐,相同宽度按钮,这样就可以产生垂直线条,若中间有空白,我们可以选中其文本对象和报表条,然后单击“缩放高度最小”就可以把中间的空白去掉。
本报表提供了自定义函数:NumToChinese,可以把数字转换为财务大写汉字,比如数字:121.56,引用此函数后,显示的结果为:壹佰贰拾壹元伍角陆分
更详细的使用说明请见:http://www.lc-simple.com/PrintTest/