制作动态数据报表----PowerBuilder_一生一念间_百度空间 相册 广场游戏 登录注册 关注此空间 一生一念间 2008-10-22 13:55 制作动态数据报表----PowerBuilder 制作动态数据报表陈冬艳 PowerBuilder是功能强大的数据库前端开发工具,深受软件开发人员的青睐,然而由于PowerBuilder所提供的报表格式较少,如果只是简单地使用PB中提供的报表对象制作报表,往往不能满足某些专业报表的制作要求,尤其是动态报表制作,因此,要想制作动态报表必须使用PowerScript脚本,在报表生成后调整各种属性设置。问题的提出 对于一张A4大小的纸,在固定好标题和注脚的位置后,其报表内容根据当时报表选择的字体、字号的不同可以容纳不同的数量,参看图1、图2。 标题 1 2 3 4 5 6 7 8 1 图1 8行/页 标题 1 2 3 4 1 图2 4行/页 如果用PB制作类似图1或图2的报表,报表中能容纳多少行数据,开发人员在设计报表对象时是未知的,只有当程序运行起来之后才能看到。如果能在程序运行过程中获取报表每页的行数,动态控制行高,就可以实现动态调整报表每页行数的功能。 PowerBuilder中的报表分两种,一种是直接用数据窗口(DataWindow)做报表,一种是使用PB的报表控件和报表对象(Report)制作报表。如果程序对报表的要求不是很特殊,使用Report就能制作符合要求的报表。用Report制作报表的局限性在于:一旦对Report的格式、内容、所挂的表及显示的列进行设置之后,就不能在运行时修改这些设置,当然也就不能满足在程序中动态设置报表各种属性的要求。而数据窗口则灵活得多,它的各种属性都可以在程序中动态设置,因此对于有特殊要求,尤其是在打印之前需要做格式调整的报表来说,使用数据窗口无疑是更方便、灵活的。 使用数据窗口做打印报表,与制作显示数据的数据窗口的过程和技巧一样,只是要在其放置的窗口上加上打印功能,用Print(DataWindow)命令,将其输出到打印机上即可,因而开发人员可以集中精力专心制作报表的各种功能。下面就介绍三种使用数据窗口制作动态报表的方法。控制打印行数 一般来说,报表只是供打印输出的,很少有人关心报表每页可以容纳多少行数据。而且大家也知道,数据窗口中每页有多少行数据在开发过程中是未知的,那么,能不能在程序运行的过程中,动态地设置报表每页的行数呢? 事实上,要想实现打印行数的控制,关键问题在于控制DataWindow对象的细目带(Detail Band)的高度(Height)。 图3 数据窗口的Print.Preview = No,此时,LastRowOnPage = 6 控制Detail Band高度的方法有两种,一种方法是计算法:即把DataWindow对象的Units属性改为1/1000厘米,然后得到Print Paper(打印纸)的高度(单位厘米),用此高度减去Header Band、Summary Band、Footer Band的高度,再除以每页打印的行数即得到Detail Band的高度。公式如下: Detail.Height =[Paper.Height -(Header.Height + Summary.Height +Footer.Height)]/(行数/每页) 图4 数据窗口的Print.Preview = Yes,此时LastRowOnPage = 40 另一种方法是:不改变DataWindow对象的Units属性,Units仍为PBU,然后在程序运行过程中读取当前DataWindow每页的行数,与用户输入的行数做比较,若当前行数大于用户输入行数,则将Detail Band的Height增大,若小于则减小。 在两种方法中,我个人认为后一种方法比较好。首先,PBU是PB定义的系统单位(不是Windows系统的单位,是PB自己的系统单位),它根据机器安装的系统字体信息(Windows系统字体)计算自己的PBU单位,这样起码从移植性来说要比前一种方法好;其次,第一种方法由于计算公式中有除法,所以结果有可能是小数,程序可能不好控制,而第二种方法使用的是PBU单位,一般来说都是整数运算,程序的控制部分相对简单一些。 应用第二种方法实现打印行数的控制,首先需要知道数据窗口中与此相关的几个属性。 1. LastRowOnPage Property PB的数据窗口有一LastRowOnPage属性,它的作用是:记录数据窗口在当前打印模式下每一页中最后一行记录的行号。例如:在数据窗口处于非打印模式时,每页有5条记录,那么LastRowOnPage的值为5、10、15……;同样是这个数据窗口,如果在打印模式下,每页可以容纳30条记录,那么LastRowOnPage的值为30、60、90……,显然LastRowOnPage的值和数据窗口当前的打印模式和当前页面有关。 PB的数据窗口有两种模式:非打印模式和打印模式。这两种模式之间的切换是通过Modify语句,将数据窗口的Print.Preview属性设置为Yes或No实现的。缺省情况下,通过窗口的数据窗口控件所显示的数据窗口对象Print.Preview的值为No。此时,数据窗口对象中页面的大小和数据窗口控件的大小相同,也就是放置在窗口上的数据窗口控件中能够显示多少行数据,则数据窗口对象的页面也只能显示同样多的数据,如图3所示。 而一般来说,此时LastRowOnPage的值并不是真正打印时,每页最后一条记录的行号。因此只有在数据窗口对象处于打印模式下,LastRowOnPage的值才是每页的最后一条记录的行号,如图4所示。 使用LastRowOnPage属性需要注意的一点是:当前数据窗口中必须有数据。如果数据窗口中无数据,则该值为0;如果数据窗口中的数据不足一页,则该值只是最后一条记录的行号。因此,若要在程序中实现打印行数的控制,必须保证数据窗口中的数据足够多,尤其是使用External数据源的数据窗口,在加载打印数据之前必须加载足够一页多的数据,取得LastRowOnPage的值,然后进行调整。 2. Detail Band Detail Band姑且称它为细目带,是数据窗口对象加载、显示、编辑数据的地方。从后台数据库取出的记录被全部加载到细目带中,因此,它也是报表打印中一个需要调整的重要部分。 Detail Band的一行显示一条数据库记录,因此,打印时每页可以容纳多少行数据和Detail Band的行高有关。在标题带(Header Band)、注脚带(Footer Band)和统计带(Summary Band)的高度定义好以后,Detail Band的高度就是决定每页可打印行数的关键。 数据窗口的Band属性有多种,其中我们要用到的一个是Height属性。在程序运行时可以使用Describe语句及时获得Detail Band的Height属性,然后,根据用户需求,用Modify语句调整Height的值,实现打印行数的控制。 3. 代码实现 (1)新建一External数据源、Grid风格的数据窗口(根据程序需要使用External数据源,使用其他数据源生成的数据窗口原理类似); (2)新建一窗口,在其上放置数据窗口控件,并把数据窗口控件的数据窗口对象属性赋予刚才建立的External数据窗口; (3)在窗口的Open事件中写入如下代码: long i long li FOR i = 1 TO 40 li = dw_print_modify.InsertRow(0) dw_print_modify.SetItem(li,1,string(i)) dw_print_modify.SetItem(li,2,string(i)) dw_print_modify.SetItem(li,3,string(i)) ...... NEXT dw_print_modify.Modify("DataWindow.Print.Preview = Yes") li_pagerow_user=long(dw_print_modify.Describe("DataWindow.LastRowOnPage")) -1* sle_pagerow.Text = string(li_pagerow_user) 上述代码的作用就是加载足够多的数据,保证这些数据能够装满一页,然后取得LastRowOnPage的值。 注意上述代码中做了标记*的部分,减1的目的是为了给Summary Band留出空间。因为PB中的Summary Band是在全部数据加载完毕后才显示或打印出来,而在初始化DW的时候,由于不知道DW中的数据最多可以容纳多少行,则若循环终值设成40,那么DW中的第一页的最后一行占据了Summary Band的地方,所以DW实际容纳的数据的行数要减去1。 (4)在窗口上放置单行编辑框(Sle_pagerow),作为用户输入的接口,将调整Detail Band行高的代码写在单行编辑框的Modify事件中,如下: long li_row // 用户输入的行数 long li_page_modify //调整Detail高度后每页的行数 long li_detail //Detail Band的高度(整数) string str_detail // 用Describe语句取出的行高 li_row = long(This.Text) + 1 str_detail = dw_print_modify.Describe("DataWindow.Detail.Height") // 得到Detail Band的高度 IF li_row 〉 li_pagerow_user THEN // 如果输入的行数大于当前行数,则高度减小 li_page_modify = li_row IF li_page_modify 〉= 1 THEN DO li_detail = long (str_detail)// 将取出的高度转变成整数 li_detail = li_detail - 1// 高度减小 str_detail = string(li_detail)// 将高度转变成字符串 dw_print_modify.Modify("DataWindow.Detail.Height = " + str_detail) // 修改Detail Band的高度 li_row= long(dw_print_modify.Describe("DataWindow.LastRowOnPage")) LOOP WHILE li_row 〈 li_page_modify // 若调整后的行数大于等于用户输入的行数则停止 li_pagerow_user = li_row - 1 sle_pagerow.Text = string(li_pagerow_user) ELSE MessageBox("提示信息","每页不能少于1行",information!,OK!) END IF ELSE // 如果用户输入的行数小于当前行数则高度增大 li_page_modify = li_row IF li_page_modify 〉= 1 THEN DO li_detail = long (str_detail) li_detail = li_detail + 1 str_detail = string(li_detail) dw_print_modify.Modify("DataWindow.Detail.Height = " + str_detail) li_row=long(dw_print_modify.Describe("DataWindow.LastRowOnPage")) LOOP WHILE li_row 〉 li_page_modify // 若调整后的行数小于等于用户输入的行数则停止 li_pagerow_user = li_row - 1 sle_pagerow.Text = string(li_pagerow_user) ELSE MessageBox("提示信息","每页不能少于1行",information!,OK!) END IF END IF 上述代码在PB 6.5、Win 95环境下调试通过。使DW中的数据垂直居中 凡是使用过PB的人都知道,PB是面向对象的开发工具,开发过程充分体现了对象的概念。比如:在数据窗口对象的设计中,我们要想让Detail Band中的每一列数据都横向居中排列,要设置列的Alignment属性为Center。 但是,用户提出要数据在列中垂直居中的要求,如果数据格式没有变化,我们也许可以做到,只要多次调试行高、字体、字号找到一个比较合适的位置就可以了。然而如果数据的格式不固定,或用户想在打印之前选择不同字体、字号的情况下,这种方法就不适用了。 例如:用户要求的报表格式为: 图5 用户要求的打印格式 那么就需要程序在加载数据的时候做到让第一行中E字段的数据垂直居中。如果不用PowerScript编写代码,那么用PB的数据窗口直接显示的结果见图6: 图6 PB的DW生成的结果 PB中没有提供专门处理数据垂直居中的函数,列属性中也没有相应的属性,因此实现列数据的垂直居中就要使用PowerScript脚本编写代码,通过动态设置列对象的各种属性实现这一功能。 思路是:将需要调整的E字段的Y值,加上一个变化量,也就是下移该字段的长度。使用Modify语句,调用DW中的表达式If(b,t,f),根据E字段的数据设置不同Y值。假设:E字段和ID字段在同一行上,有相同的Y值,不论用户是否调整Detail Band的行高,ID列的Y值是不变的。使用Modify,判断如果E列中的数据大于6(视情况而定),则将E列的Y值加上(下移)20(同样视情况而定),否则,Y值等于ID列的Y值。 代码如下(在放置数据窗口的窗口中再放置一命令按钮,在按钮的Clicked事件中写入代码): string str_col_name // 字段名 string str_pos_y // 欲调整字段的Y值 string modstring,str_rtn long li_pos_y // 欲调整字段的Y值(整型) str_col_name = "列名" str_pos_y = dw_print_modify.Describe(str_col_name + ".Y") li_pos_y = long(str_pos_y) // 初始条件:所有列都在同一行上,Y值相同 modstring = str_col_name + ".Y = '" + str_pos_y + " ~t if( Len( " + str_col_name + " )〈= 8 ," + string(li_pos_y + 15) + "," + string(li_pos_y - 10) + ") '" str_rtn = dw_print_modify.Modify(modstring)设置字体“胖瘦” PB中字体Font对象有个Width属性,但是一般来说用不到它,因为Windows系统已经内置了诸多字体,各个字体的信息都已设置好。我们只需根据不同的需要,把不同字体名FontName(如宋体、楷体)赋给所使用的对象的字体名属性即可。 但是在报表打印输出的时候,尤其是Grid风格的报表,表格带有边框线,若列数据的长度超过了列允许的长度,那么后面的数据就看不到了。怎样在固定好列长度之后动态调整字体宽度,以便超过长度限制的数据能排在一行中呢? 解决的办法就是动态设置Width属性。Font.Width属性值可为整型数字,程序员可以根据自己的需要进行设置。通过试验发现,在PB中普通系统字体对应的Width值在45~50之间,小于这个值则字变瘦,大于这个值则字变胖。Width值在每次变化量为2的情况下,人眼在屏幕上可看出明显变化。 通过Modify语句修改Width的代码如下: string str_col_name// 列名 string str_rtn // Modify语句返回值 string modstring modstring = str_col_name + ".Font.Width = '" + string(45) + " ~t if( Len(" + str_col_name + " ) 〈= 16 ," + string(45) + "," + "if (Len( " + str_col_name + ") 〈= 18 ," + em_think.Text + "," + string(long(em_think.Text) - 2) + ") )'" str_rtn = dw_print_modify.Modify(modstring) 上述代码实现的功能是:假设列允许的长度为16个英文字母(8个汉字),则小于16的数据,字体宽度为45(即普通系统字体宽度,近似值),长度大于16而小于18的数据,字体宽度为em_think(EditMask编辑屏蔽框)中设置的数字大小,而长度大于18的数据的字体宽度为em_think的整型数字减去2。 #PowerBuilder 分享到: 举报 浏览(1018) 评论(2) 转载 你可能也喜欢 动漫,我喜欢你——2 战斗+超能力+侦探=滨虎? 14/1/8 简论凉宫春日物语一个等级的轻小说 【音乐】TVアニメ「境界の彼方」EDテーマ -「Daisy」/STEREO DIVE FOUNDATION [通常盤] LOVELESS 虫师动画特别篇结尾处出现的第二季人物预告 在C#中使用控件DataGridView实现数据库增删改查 本文最近访客 chengadvice 吃饱了混 Dickhuazai glovlily163 xiangxinflyhi xuzhengyang911 wang_pt 评论 帮助中心 | 空间客服 | 投诉中心 | 空间协议©2014 Baidu