5.Report组件
问1.如何学习和数据源相关的报表开发?
1.请参考“开发者指南”中“Supcan Report组件”的“附录:数据源实例”,完全按照其步骤实战一遍;问2.点了工具条上的“保存”按钮,报表怎么没保存到服务器端啊?
Report本身并不具备上传文件的能力,该“保存”功能必须要和页面js、服务器端程序结合才能生效。具体做法如下:function OnEvent(id, Event, p1, p2, p3, p4) { if(Event == "Toolbar" && p1=="104") { //若用户点击保存按钮,将立即触发该事件 var xml = AF.func("GetFileXML", ""); ... //Ajax发送 xml 串,(略) ... AF.func("CancelEvent", ""); //该函数很重要,表示不再执行按钮的后续默认动作 } }方案三:
function OnEvent(id, Event, p1, p2, p3, p4) { if(Event == "Saved") { AF.func("HttpPostLocalFile", "http://localhost/WritePost.aspx?fun=AD91 \r\n" +p1+ "\r\n mode=asynch"); return; } }本方案最简单, 但硕正插件 1.0.104.0 版本后才支持.
问3.报表的工具条、编辑设计功能都很丰富,这到底是为开发设计人员用还是为最终用户使用?
Demo页只是全方位展示Report丰富的功能,最终部署到应用程序时,可以根据需要裁剪掉一些功能。问4.Treelist、Freeform 都有 XML 文档规范可参考,为什么 Report 的 XML 文档规范没有公布?
因为Report本身就是一个设计器,你设计好后“另存”到本地文件即可。此外,Report 的 XML 格式远比 Treelist、Freeform 复杂,手写 XML 很难设计出复杂的报表。问5.怎样控制按数据类型输入,比如数值型只能输入数字、日期型只能输入日期?
打开工具条左侧的“属性”对话框(如右图所示),选中“启用单元格的数据类型校验(在输入时)”: 但是请注意,该选项在设计时(DesignTime)是不起作用的. |
![]() |
问6. 硕正报表有没有类似 Excel 的表头冻结锁定功能?
有,鼠标滑过报表上标尺上方、左标尺左侧,会改变形状的,此时向下、向右拖拽即可(见右图): 此外,执行 SeparateView 函数也可以达到同样效果. 保存该报表模板,当下次再打开,该冻结仍能生效,行列冻结信息是随报表XML一起保存的. |
![]() |
问7.我明明修改了报表并保存了,下次打开发现还是修改前的报表,这是怎么回事?
是浏览器缓存或Web服务器的原因,和硕正控件毫无关系,关于缓存,请参考 “3.安装、部署和运行” 中的 "问14.经常发现貌似浏览器缓存...".问8.我某张报表很大,有好几兆,所以上传很慢,有没有加速的方法,比如压缩?
有办法:function OnEvent(id, Event, p1, p2, p3, p4) { //自定义103(保存)功能号 if(Event == "Toolbar" && p1 == "103") { //1.调用全局函数 CacheDirUtility, 生成临时文件 var tempfile = AF.func("CacheDirUtility", "isCreateTempFile=true;ext=xml"); //2.调用104功能号, 保存报表到临时文件 AF.func("callfunc", "104 \r\n" + tempfile); //3.调用全局函数 HttpPostLocalFile, 压缩上传, 注意 compress=zip 选项 AF.func("HttpPostLocalFile", "http://192.168.1.1/nse/get.aspx?id=10203 \r\n" +tempfile + "\r\n compress=zip; mode=asynch"); //4.终止默认的后续动作 AF.func("CancelEvent", ""); return; } }报表是以 zip 格式压缩的,您的后端程序可以直接把二进制流写到文件或保存到数据库,没必要解压。下次打开报表,可以直接返回这个二进制流, 因为硕正控件能识别 zip 流、自动解压的.
问9.采用Supcan Report设计好报表后,如何保证让最终用户既能编辑格式、但又不改坏已定义好的临时数据源?
建议您采用包含如下功能的方案:问10.如何实现报表仅用于被查询而不被修改?或报表中部分内容不被修改?
首先,要区分是什么工作模式:上报模式和非上报模式(即普通模式),以下将单独说明:AF.func("Swkrntpomzqa", "1, 2");如果要让某些单元格不被修改,最简单的办法就是为单元格设置 “保护” 属性。请注意:“保护” 属性无法单独起作用,必须结合 Swkrntpomzqa 函数才能生效:
AF.func("Swkrntpomzqa", "16");“保护” 是需要手工逐个单元格预先设置的,如果您嫌这个步骤麻烦,那么可以参考开发文档中的其它权限类函数,比如 addEditAbleOnly( )、addUnEditAbleOnly( ) 函数,其功能非常强大,例如下例表示仅红色背景色的单元格能够修改:
AF.func("addEditAbleOnly", "bgClor=red"); 或 AF.func("addEditAbleOnly", "bgClor='#FF0000'");除了颜色,还有其它的属性可以用于判断,详情请参考该函数的使用文档.
问11.我设计好报表、填入数据源的数据,然后将报表另存,当我再次打开这个报表(XML文件)后,发现填入的数据不见了,这是怎么会事?
在默认情况下,报表永远是以“模板”的形式保存的,模板是不包含从数据源中取到的数据的,也就是说在保存时,临时剔除了填入的数据。当报表再一次在页面中展示时,需要在OnReady( )事件中书写代码以取数、填充、展现。您明白这个机理了吗?问12.我更改了打印的设置(如页边界、分页参数),如何保持住这些参数?
打印的所有参数,都是保存在XML模板文件中的。你修改了打印设置,需要保存一下模板(或上传到服务器).问13. 为什么在打印预览中明明 1 张纸能打印得下,真正打印时却打印了2张纸?
不可能的,因为硕正控件的源码中,预览和打印是使用同一个分页程序的。问14.如何实现同类单证的连续打印?
通常需要写如下的循环:AF.func("Build", "reports/aax.xml"); //打开模板 for( ... ) { //自己写循环 //假设是临时数据源, 设置查询取数条件 (即更改数据源) AF.func("SetSource", "ds1 \r\n abc.aspx?mon=" + mon); //计算 (备注:必须同步计算,不能选异步) AF.func("Calc", ""); //打印, 变量 isOpenDlg 用来控制是否弹出对话框, 通常第一遍循环中设为1,其余的为0,这样打印对话框就只弹出一次 AF.func("Print", "isOpenSysDialog=" + isOpenDlg); }如果循环中需要切换报表模板,那就把第一行移入循环.
问15.我在报表打印配置对话框中自定义了打印纸,为什么有的电脑打开这个报表时,会出现如下提示?
是有这个可能的. 自定义打印纸的尺寸信息是包含在报表XML中,当控件在打开报表后, 会尝试着去创建这个自定义打印纸,但是创建过程可能会失败,失败原因就在于操作系统分配给浏览器的权限不够. 如果创建失败, 您只能在 "开始" 菜单 \ "设备和打印机" 中选择打印机, 然后在上方的 "打印机服务属性" 对话框中去手工创建(见右图). |
![]() |
此外,如果你的打印机不支持自定义打印纸、或者自定义打印纸正好是标准打印纸 (如A4、A3) 的 n 分之一,你就不必去创建自定义打印纸了,改而使用这个选项: (见右图) | ![]() |
问16. 我使用了自定义打印纸,并用针式打印机打印的,发现打印1、2张没问题,但在连续打印时,上下偏移误差会越来越大,这是什么原因?
问17. 我使用了自定义打印纸,并用针式打印机打印的,左右边距都设成2毫米,在预览中表格线能紧挨左侧的虚线(边距标记), 一切正常, 但是实际打印时, 左侧会留出太多的空白, 这是什么原因?
可以推测, 表格线左侧约 2 毫米的位置, 应该就是打印头的 x 轴坐标原点,如右图箭头所指: 既然该打印机支持穿孔打印纸,那么在它的背后的滑杆上应该有两个穿孔咬合处,其位置是能微调的,将它们整体往右移动约1厘米,应该就正常了. |
![]() |
问18. 为什么打印预览时表格都是居中的,但是真实打印出来,左边距会比右边距多大约1厘米?
大多数情况下,将模版中的这个选项选 "不忽略" 即可正常,因为不同打印机的物理有效边距有轻微差异 (见右图): 在设计报表模板时,幅面大小不要满打满算,应该考虑到打印有效边距因素、以及软件的误差因素. |
![]() |
问19. 我在打印配置中选择了使用某台打印机, 但是下次打开这报表发现又变成其它打印机了, 能固定住吗?
下次进去时, 肯定是采用当前操作系统的默认打印机的。如果你想固定用某台打印机打印,必须勾选下方的 "认定用这台打印机打印" 复选框(见右图). 在网络环境下, 其它电脑也使用这个模板时, 硕正插件首先会去本地查找同名打印机,如果找不到,则又切换回本地操作系统的默认打印机了. |
![]() |
问20.我不想在页面中出现报表控件,只是想调用CallFunc函数直接打印,所以我把 div 的高、宽设为1px,为什么经常会不稳定,似乎控件没有创建?
你把高、宽各设成 2px 就很稳定了,估计和浏览器对div的渲染有关.问21.继续上一个问题,我把 div 的高、宽设为2px,但还是有个白色(或黑色)的小点,能去掉它吗?
在它的 OnReady 事件中,将它的div容器隐藏即可。隐藏div 可设置 visibility 为 hidden, 不建议用display="none" 。... function OnReady(id) { var container = document.getElementById('dv1'); container.style.visibility='hidden'; AF.func("Build", "report/report1.xml"); AF.func("callfunc", "18"); } </script> </head> <body> <div id="dv1" style="position:relative;width:2px;height:2px"><script>insertReport('AF', '')</script></div> </body> </html>
问22.我在学习带参数的数据源,是不是URL中的变量如 "test.aspx?y=2011&mon=23&dept=A1" 中的 y、mon、dept都必须当作参数?
不是的,报表中的“参数”是指内容取自单元格的参数,像固定的、或由js控制的变量就不能算是“参数”.问23.中心数据源或临时数据源,有很多处的URL(例如 dataURL)属性,如果采用相对URL,到底相对谁?
遵循这2个规则: 1.谁定义,就相对谁; 2.斜杠("/")开头表示相对根目录。问24.电子表单通常分二部分:表头(master)和表体(detail),硕正Report能实现吗?
请参考demo页“报表 - 精确打印 - 套打(一)”,这应该就是您所要的。 或者,也可以参考下Freeform的demo页“9.有表头表体的表单(2)”问25.我们的数据服务都设计成 rest 方式调用的WebService,请问应该怎样和硕正的数据源配套使用?
选择普通的XML数据源(包括临时数据源或中心数据源)就行,而不是硕正Web Service数据源,因为硕正WebService数据源仅用于POST的、非rest方式的.问26.我用 NotePad 打开一张使用了中心数据源的报表XML文件,发现其中有中心数据源的列结构的详细信息(即所谓“数据源模版”),这些列结构有什么用呢?
在大多数情况下,这些列结构信息确实没啥用处,因为报表在展现时,列结构将强行和后端的中心数据源同步. 但是如果你修改了列的显示名(标题)、列的显示顺序、是否隐藏等等,那么这些信息就有用了。问27. SetSource( ) 函数到底应该在 Build( ) 函数前执行还是后执行?
如果是临时数据源,必须先执行Build( ),再执行 SetSource( ); 如果是中心数据源,则应该先执行 SetSource( ),因为它是全局有效的, 对今后的新增报表都能生效.问28. 我使用了中心数据源,执行了
AF.func("SetSource", "../dscenter.aspx?id=337")
然后通过Build打开报表模板、正常计算,没问题。然后在另一个页面执行
AF.func("SetSource", "../dscenter.aspx?dept=mnger");
然后通过Build打开报表模板,发现总是只有一张报表能计算,另一张计算不了,为什么?
问29. 我使用了中心数据源,用XML查看器直接查看报表的XML文件中的数据源描述部分,发现里面有一个中心数据源的URL(即下面<Source>内容):
是不是意味着不需要执行SetSource函数?
问30. 报表中使用了超链接,有时候是直接打开了链接页面,有时候没反应,这有什么规律吗?
如果你预订(SubscribeEvent) 了Clicked事件,那么只抛出Clicked事件,不会打开超链接页面的;否则则相反,只打开链接页面、不抛出事件.问31. 我想在页面 js 脚本中直接调用数据源中的数据,可以吗?
可以,请参考“全局函数”文档中的 “5.对 计算函数 的封装”。但你只能调用 data、head 这些单个数据,无法调用 datarow、headrow 这些块状的数据.问32. 我想对报表中数据源填充区域做一个合计,例如在 =datarow( )函数的下一行写 =sum(D4:D20),但无法预计数据有多少行,不知道D20这样写对不对?
报表在线演示中有很多这方面的演示页的,例如右图: 关键就是需要“@单元名”宏,详细请参考 "公共内容" 中的 "3.宏". |
![]() |
问33. 报表中的单元格怎样让它使用下拉?
首先,您必须在报表中先设定“字典”,字典功能在“工具箱”上方第四个小按钮中;问34. 我想把当前报表复制到一个新建的工作表中,该怎么做?
直接复制工作表的功能是没有的,但可以这样实现://取得本地的一个临时文件 (注: CacheDirUtility 函数是全局函数,请参考“全局函数”文档) var filename = AF.func("CacheDirUtility", "isCreateTempFile = 1"); //调用 1074 功能号,把当前报表另存到临时文件 (注:请参考工具条功能号文档) AF.func("callfunc", "1074 \r\n" + filename); //添加工作表 AF.func("AppendWorkSheet", filename);
问35. 怎样动态地用 js 往报表中插入图片?
有二种方法://插入别名为 "MyPic" 的文本框 AF.func("callfunc", "112 \r\n x=10; y=20; width=200; height=140; alias=MyPic"); //将其数据类型改成字符串型 AF.func("SetCellProp", "MyPic \r\n dataType \r\n string"); //添加图片显示掩码 var id = AF.func("Mask_Add", "string \r\n =picture()"); //修改它的显示掩码, 至此,该文本框就以图片显示了 AF.func("SetCellProp", "MyPic \r\n maskId \r\n" + id); //赋图片: 通过 SetCellData 赋值就行 AF.func("SetCellData", "MyPic \r\nDotNet/res/aa.jpg"); //设置其它效果:背景色为透明、无边框 AF.func("SetCellProp", "MyPic \r\n bgColor \r\n T"); AF.func("SetCellProp", "MyPic \r\n borderThick \r\n 0"); //刷新一下屏幕 AF.func("SetRedrawAble", "true");
问36. 我按照 “20.分类汇总” 做了个分类汇总表,汇总计算结果含有千位符,怎样才能不显示千位符呢?
修改一下那个汇总表达式,把里面的 @sum 替换成 replaceAll(@sum, ',', '') 或 formatNum(@sum, '#.00')问37. 数据源加载的数据,为什么有些单元格显示为诸如“5.405297231E7”这种科学计数法?
这个串来自你的XML/JSON数据包,如果在数据源中该字段设为 string 型,报表控件是原封不动将其显示的。问38. 报表的 PDF 格式导出,发现内部是图片,能否导出纯文字啊?
目前尚未支持,但有一简单的办法:安装一个 adobe pdf虚拟打印机吧.问39. 我需要用 js 执行大量的 GetCellData, SetCellData, GetCellProp, SetCellProp等等存取单元格信息的函数,以前速度很快,但不知道是什么原因,有时候速度奇慢,这是怎么回事?
导致慢的通常有2个原因。问40. 我这样写,分别调用163(计算)、18(预览)功能号,为什么第二句永远不执行?
AF.func("CallFunc","163"); AF.func("CallFunc","18");因为163功能号 (即按钮点击 “计算”) 是异步计算,所以你应该用 Calc 函数,不要调用 163 功能号。
问41. 工具栏中的“计算”按钮(即齿轮图标),和函数 Calc( ) 有什么差别?
差别不大,插件内部都是调用同一个内部函数的,只是按钮启动的是异步计算,相当于是执行了 AF.func("calc", "mode=asynch; range=full")。问42. 关于分类汇总表或交叉表,我看例子中,旁边都配有一个纯数据的工作表,这个工作表可以删除吗?删除它对旁边的分类汇总表/交叉表有影响吗?
无影响,可以删除。问43. 假如 A1 单元格的计算公式为 "=E2 + F2", 然后我用 SetCellData 更改了 E2 单元格的内容,发现 A1 单元格不会自动更新,请问如何让它计算 ?
在 SetCellData 后,执行 calc 函数吧。问44. 我在 A1、A2 单元格分别输入 1、2,然后 让 B1 = A1 + A2, 结果是 3, 能否让它们以字符串方式相加,也就是说结果是 “12” ?
你应该将 A1、A2 单元格的数据类型设成字符型。问45. 我的分类汇总表如图,我怎样才能不显示 “城市” 列的重复行内容?比如 “布宜诺斯艾利斯” 只显示在第一行,下面同名的就不显示?
请在 datarow( ) 所在行的城市单元格,将它的 "显示掩码" 设成: if(ref(row( ) - 1, col( )) == data, '', data) 重新计算后,结果就这样了(如右图): |
![]() |
问46. 单元格内的文字, 怎样强制换行? 比如下面是自动换行, 我怎样才能在 "实际" 处断行 ?
问47. 我用了分页小计函数 =PageSum('D'), 打印预览时是正确的, 但显示时, 却会显示成 1.0 或 0.0, 能否做到普通显示时不显示, 单元格留空?
把公式改成诸如这样吧:= if(Pages()==0, '', pageSum('D'))