| 
				 摘  要:本文主要介绍了在使用Visual Foxpro 编写数据库应用程序时,如何根据实际需要随机选取字段生成自由报表。 
关键词:VFP    数据库     
  
一、存在的问题  
 用VFP报表生成器生成的报表,对于用户所需的某一数据库的任意字段组合报表,就显得不是那样运用自如。因为,一方面软件开发时,无法考虑到日后用户所需报表的所有格式。另一方面,由于所设计好的报表格式文件已编译成可执行文件,即使修改了.FRX和.FRT文件结构内容,也需在开发环境下重新编译,对用户来讲是无法实现的。例如职工档案库中有许多项目,需一份职工职称年龄表,进行报表上报,此类问题就比较难解决。  
二、解决方案  
1.自己编写一个简单的报表生成程序,可以根据随机选取的字段生成表头、表格线及打印项目,将报表每一行看做是一条记录,然后进行报表打印。 
2.运用VFP与Excel 的交换数据及在VFP中全面控制Excel的操作(即自动服务器),就可以很好的解决这一问题。关于如何控制Excel,一方面可以通过Excel的帮助文件的VBA语法,另一方面也有相当多的文章关于控制Excel的语法。值得注意的是:1、为提高效率,所有有关计算、小计、合计最好在VFP中进行,并写在相应的记录内;2、由于是两个软件,如果在有大量数据逐一插入Excel单元格时,显得速度较慢,所以如果数据量较大,应直接用VFP的数据表导出为Excel格式,再由VFP在后台控制Excel打开,并指定的Excel格式文件进行修改文档标题、列的名称、网格线型,以及根据纸张大小计算各列宽和调整字体大小。  
本文着重谈第一种方案的实现。 
三、实现办法  
首先需要创建两个表文件,一个是所要打印的数据表的结构文件,本例为DYBX.DBF;一个是已选择字段的表文件,本例为PRNTMP.DBF。 
表结构如下: 
    表结构: DYBX.DBF 
    字段   字段名            类型        宽度    小数位  
      1   FIELD_NAME        字符型        10            
      2   FIELD_TYPE        字符型         1            
      3   FIELD_LEN         数值型         3            
      4   FIELD_DEC         数值型         3            
   
    表结构:   PRNTMP.DBF 
    字段   字段名    类型       宽度   
      1    ZDM       字符型       10   
      2    ZDCD      数值型        3   
      3    ZDLX      字符型        1   
    表结构:   dyb.DBF 
    字段   字段名    类型       宽度   
      1    dybx      字符型     180   
  
然后构建如下表单,左侧列表框的数据源为DYBX.DBF,右侧GRID的数据源为PRNTMP.DBF,按钮“增加项目”的作用是将选择字段增加到PRNTMP中,“删除项目”是将右侧选择字段从PRNTMP中删除,“生成报表”是据PRNTMP内容生成用于打印输出的表,“打印报表”是用REPORT命令将生成表打印输出。 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
   
************ 
左侧列表框属性 
    recordsource=dybx 
右侧grid属性 
    recordsource=prntmp 
数据环境:DYB,DYBX,ZGB,PRNTMP, 其中DYB属性exclusive为.t.,ZGB为人员档案数据表。 
“增加项目”click代码: 
local m.i,m.n,m.mc,m.cd 
m.i=0 
sele dybx 
m.n=recn() 
m.mc=field_name 
sele prntmp 
sum all zdcd to i 
if i>160 
   =messagebox("超出表长,重新选择",64) 
else 
   sele prntmp  
   go top 
   loca for trim(zdm)==trim(m.mc) 
   if found() 
      =messagebox("已有此字段!",64) 
   else  
     m.cd=dybx.field_len 
     if dybx.field_type=='D'  &&日期型长度为10 
        m.cd=10 
     endif 
     if len(trim(dybx.field_name))>m.cd  &&名称大于字段长度 
        m.cd=len(trim(dybx.field_name)) 
     endif 
     appe blan 
     repl zdm with dybx.field_name,zdcd with m.cd,zdlx with dybx.field_type 
   endif 
endif 
thisform.grid1.refresh() 
“删除项目”click代码: 
sele prntmp 
dele 
thisform.grid1.refresh() 
* * * * * * * * * * * * * * * * * 
*生成报表按钮的程序代码 
* * * * * * * * * * * * * * * * * 
proc scbb 
local z(20),z2(20) 
dime z(20),z2(20)     
c1="┌"            &&初始化变量 
c2="┐" 
c3="┬" 
c4="─" 
c5="├" 
c6="┤" 
c7="│" 
c8="┴" 
c9="┼" 
c10="└" 
c11="┘" 
m.jls=30 
i0=0 
i1=1  
  
sele dyb          &&要打印的表 
zap 
sele prntmp       &&已选中字段的表 
go top 
l1=c1+c4+c4+c3 
l2=c7+'序号'+c7 
l3=c7+'    '+c7 
l4=c5+c4+c4+c9 
l5=c10+c4+c4+c8 
do whil !eof()                &&生成表头 
   i2=zdcd/2+mod(zdcd,2)     
   for j=1 to i2 
       l1=l1+c4 
       l3=l3+"  " 
       l4=l4+c4 
       l5=l5+c4 
   endfor 
   l2=l2+padc(trim(zdm),i2*2) 
     z(i1)=trim(zdm)    
     z2(i1)=zdcd          
     skip 
     if !eof() 
       l1=l1+c3 
       l2=l2+c7 
       l3=l3+c7 
       l4=l4+c9 
       l5=l5+c8 
       i1=i1+1 
     endif 
 enddo                     
 i0=i1 
 l1=l1+c2 
 l2=l2+c7 
 l3=l3+c7 
 l4=l4+c6 
 l5=l5+c11 
 sele dyb                  
 appe blank 
 repl dybx with l1 
 appe blank 
 repl dybx with l2 
appe blank 
 repl dybx with l4         &&生成表头结束 
sele zgb                 &&打开职工库,既要打印的职工信息 
go top 
b1=c7 
b2='' 
k=1 
j=1 
x=1 
mrec=recn() 
do whil !eof()         &&每条记录据类型生成一行打印字符 
   j=1 
   b1=c7+str(x,4)+c7 
   do whil j<=i0 
       sele zgb 
       go mrec 
       lszdm=trim(z(j))      &&字段名 
       lszdz=&lszdm        &&相应值 
       DO CASE           &&日期\数值字段变字符 
          CASE  z3(j)=’D’         &&时间字段 
               b2=dtoc(LSZDZ)  
          CASE  z3(j)=’N’         &&数值字段 
               b2=str(LSZDZ)  
          OTHE  
                b2=padl(&z(j),z2(j))  
       ENDCASE 
       b1=b1+b2+c7 
       j=j+1 
   enddo 
   sele dyb         && 加入打印库 
   appe blan 
   repl dybx with b1 
   sele zgb 
   GO MREC 
   skip 
   MREC=RECN() 
   if !eof() 
      k=k+1 
      x=x+1 
      if k>m.jls         &&换页处理 
          sele dyb 
          appe blan 
          repl dybx with l5 
          appe blan 
          appe blan 
          appe blank 
          repl dybx with l1 
          appe blank 
          repl dybx with l2 
          K=1  
      endif 
      sele dyb 
      appe blan 
      repl dybx with l4 
      SELE ZGB  
      GO MREC 
   else 
       sele dyb 
       appe blan 
       repl dybx with l5 
       EXIT     
   endif 
enddo       
retu 
  
    此程序用VFP6.0调试成功,并已在“干部职称管理系统”中运行至今。由于使用方便,客户反应良好。 
  			
				 |