先贴出来一些以前的关于水晶报表的字段方面的设置方法Dim ParaText As CrystalDecisions.CrystalReports.Engine.TextObject  //一个Label字段
Dim ParaField As CrystalDecisions.CrystalReports.Engine.FieldObject//一个数据库显示字段
Dim ParaLine As CrystalDecisions.CrystalReports.Engine.LineObject  //一条线ParaText = CType(rptRetailOrder.ReportDefinition.ReportObjects("Text2"), TextObject) 
ParaText.Left = 120  //可设置左起
ParaText.Width = GetInWidth   //可设置宽度其他同理想直接利用水晶报表直接做一个自定义报表生成器,但感觉很麻烦

解决方案 »

  1.   

    这个估计比较难的吧,我只会用Activereport,那里面的例子有自定义报表的教程:)
      

  2.   

    如果是企业用户,建议用MS SQL SERVER REPORT SERVICES.
      

  3.   

    一、用水晶报表。
    二、其他厂商提供的现成的报表。例如如意报表等。http://www.soft2web.com
      

  4.   

    三、还可考虑一下Sybase公司出的Datawindow.NET。
        http://www.sybase.com/products/internetappdevttools/datawindownet
    四、用Excel。
      

  5.   

    通常报表分两类,一是台帐式,也就是一条记录占一行,二是简历式,一条记录占一页,我一直用office代替水晶报表,用Excel做台帐式报表,用Word的邮件合并功能做简历式报表,关于台帐式报表你可以搜索我的一篇文章《在C#中用EXCEL做高级报表》,当然你也可以到我的ftp://202.107.251.26中的《C#技术文章文件夹中》下载,该文章写得较早,有些地方不太好,如填充数据时原来是一个一个单元格填充,速度较慢,现在是通过一个二维数组一次性填充,非常快,等过年后我将文章重新写一下,并介绍如何用Word做简历报表,所以这些报表都可以先通过Office按一定要求排好版作为模板保存,模板和软件是分离的,也就是可以让用户管理员随时修改、增删报表。
      

  6.   

    下面是我生成报表的实际代码,可以参考:
    /// <summary>
    /// 用Word生成一个类似个人简历的报表(通过邮件合并方式实现)
    /// </summary>
    /// <param name="p_Table">用到的Table</param>
    /// <param name="p_FileName">报表名称</param>
    private void MakeDetailReport(DataTable p_Table,string p_FileName)
    {
    //首先产生一个文本文件作为word的数据源
    string strTextFile=Tools.RandFileName+".txt";
    string strValue; //很多表中都要用到操作信息,如制表人,这里单独用一个变量来表示其位置
    string strOpPos="";
    //====接下来打开word模板进行处理===//
    Object Nothing=System.Reflection.Missing.Value;
    //打开模板文件
    Word.Application myApp=null;
    Word.Document myDoc=null;
    myApp=new Word.ApplicationClass();
    object ob=(object)p_FileName;
    myDoc=myApp.Documents.Open(ref ob,ref Nothing,ref Nothing,ref Nothing,ref Nothing,
    ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,
    ref Nothing,ref Nothing);
    myApp.Visible=true; //读入最后一行,得到值对应的单位表格位置
    strValue=myDoc.Paragraphs.Last.Range.Text.ToString();
    strValue=strValue.Replace(" ","");
    //去掉用于存放数据的最后一行
    myDoc.Paragraphs.Last.Range.Delete(ref Nothing,ref Nothing);
    ArrayList arrCell=new ArrayList();//某单元格的内容(行,列,字段名)
    ArrayList arrTable=new ArrayList();//该字段位于一条记录中的第几列
    //分离出各邮件合并用到的单元格数据
    int nColCount=p_Table.Columns.Count;
    foreach(string s0 in strValue.Split(';'))
    {
    //得到行、列、字段名
    string []s1=s0.Split(',');
    if(s1.Length<3)
    continue;
    string fieldname=s1[2];
    //操作员特殊处理
    if(fieldname=="{操作员}")
    {
    strOpPos=s0;
    }
    else
    {
    for(int i=0;i<nColCount;i++)
    {
    if(p_Table.Columns[i].Caption==fieldname)
    {
    arrCell.Add(s0);
    arrTable.Add(i);
    break;;
    }
    }
    }
    } //=========写入rp中的内容=====//
    StreamWriter writer=new StreamWriter(strTextFile,false,System.Text.Encoding.Unicode);
    int nCount=arrCell.Count;
    //写入标题
    for(int i=0;i<nCount;i++)
    {
    strValue=(arrCell[i] as string).Split(',')[2];
    if(i>0)
    strValue=","+strValue;
    writer.Write(strValue);
    } //写入具体数据
    int nRowNum=p_Table.Rows.Count;
    for(int i=0;i<nRowNum;i++)
    {
    writer.Write("\r\n");
    strValue="";
    for(int j=0;j<nCount;j++)
    {
    string strField=(arrCell[j] as string).Split(',')[2];//列名 //如果是当前Table,直接从DataGrid中取,这样可以保证按用户排序进行输出
    if(p_Table==m_Table) //直接从当前表中提取的
    strValue=this.dataGridInfo[i,(int)arrTable[j]].ToString().Trim();
    else
    strValue=p_Table.Rows[i][(int)arrTable[j]].ToString().Trim();
    //将时间转换成符合中国习惯
    if((strValue.Length>0) && (p_Table.Columns[(int)arrTable[j]].DataType==typeof(DateTime)))
    {
    DateTime dt=DateTime.Parse(strValue);
    strValue=String.Format("{0}年{1}月{2}日",dt.Year,dt.Month,dt.Day);
    //如果有时分
    if(dt.Hour>0 || dt.Minute>0)
    {
    strValue+=String.Format(" {0}时{1}分",dt.Hour,dt.Minute);
    }
    }

    //为使报表不错误,替换掉可能产生的逗号回车
    strValue=strValue.Replace(",",",");
    strValue=strValue.Replace("\r\n","");
    strValue=strValue.Replace("\t","");
    //如果不是第一列,则加入一个逗号来分隔
    if(j>0)
    strValue=","+strValue;
    writer.Write(strValue);
    }
    }
    writer.Close(); //开始添加邮件合并
    object bFalse=(object)false;
    object bTrue=(object)true;
    object sFormat=(object)"wdOpenFormatAuto";
    myDoc.MailMerge.MainDocumentType=Word.WdMailMergeMainDocType.wdEnvelopes;
    myDoc.MailMerge.OpenDataSource(strTextFile,ref sFormat,ref bFalse,ref bFalse,ref bTrue,
    ref bFalse,ref Nothing,ref Nothing,ref bFalse,ref Nothing,ref Nothing,ref Nothing,
    ref Nothing,ref Nothing); //逐单元格填充
    foreach(string s in arrCell)
    {
    string name;
    int row,col;
    string []s1=s.Split(',');
    row=int.Parse(s1[0]);
    col=int.Parse(s1[1]);
    name=s1[2];
    myDoc.Tables.Item(1).Cell(row,col).Select();
    myDoc.MailMerge.Fields.Add(myApp.Selection.Range,name);
    } //写入当前操作员信息
    if(strOpPos.Length>0)
    {
    int y=int.Parse(strOpPos.Split(',')[0]);
    int x=int.Parse(strOpPos.Split(',')[1]);
    myDoc.Tables.Item(1).Cell(y,x).Range.Text=Tools.OpInfo.OpName;
    }
    myDoc.MailMerge.Destination=Word.WdMailMergeDestination.wdSendToNewDocument;
    myDoc.MailMerge.MailAsAttachment=false;
    myDoc.MailMerge.MailAddressFieldName="";
    myDoc.MailMerge.MailSubject="";
    myDoc.MailMerge.SuppressBlankLines=false;
    myDoc.MailMerge.DataSource.FirstRecord=1;
    myDoc.MailMerge.DataSource.LastRecord=m_Table.Rows.Count;
    myDoc.Save();
    myDoc.MailMerge.Execute(ref bTrue);
    myDoc.Close(ref bTrue,ref Nothing,ref Nothing); }
      

  7.   


    /// <summary>
    /// 用EXCEL生成台帐式报表
    /// </summary>
    /// <param name="p_FileName">生成的EXCEL文件</param>
    /// <param name="rpTable">存放数据的TABLE</param>
    /// <param name="p_TableName">报表名称</param>
    private void MakeListReport(string p_FileName,DataTable rpTable,string p_TableName)
    {
    this.ShowFLW("正在生成报表,请稍等……");
    //时间较长,改变光标形状
    this.Cursor=System.Windows.Forms.Cursors.WaitCursor; //设置进度条
    this.progressBar.Maximum=rpTable.Rows.Count;
    this.progressBar.Minimum=1;
    this.progressBar.Value=1;
    Application.DoEvents(); try
    { object missing=Missing.Value;
    Excel.Application myExcel=new Excel.Application ( );
    //打开新文件
    myExcel.Application.Workbooks.Open(p_FileName,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing,
    missing);  //得到当前的工作簿
    Excel.Workbook myBook=myExcel.Workbooks[1];
    Excel.Worksheet mySheet=(Excel.Worksheet)myBook.Worksheets[1]; //得到操作员等特殊信息的存放位置
    Excel.Range r=mySheet.get_Range(mySheet.Cells[1,1],mySheet.Cells[1,1]);  //取得值存放的区域
    string strValue="";
    if(r!=null)
    strValue=r.Value.ToString();
    foreach(string str in strValue.Split(';'))
    {
    string[] strInfo=str.Split(',');
    if(strInfo.Length!=3)
    continue;
    string strMessage="";
    switch(strInfo[2])
    {
    case "{操作员}":
    strMessage=Tools.OpInfo.OpName;
    break;
    case "{公司名称}":
    ArrayList arr=new ArrayList();
    string strCompany;
    foreach(DataRow row in rpTable.Rows)
    {
    strCompany=row["公司名称"].ToString();
    if(arr.IndexOf(strCompany)<0)
    {
    arr.Add(strCompany);
    strMessage+=strCompany;
    }
    }
    strMessage=rpTable.Rows[0]["公司名称"].ToString();
    break;
    }
    if(strMessage.Length>0)
    mySheet.Cells[int.Parse(strInfo[0]),int.Parse(strInfo[1])]=strMessage;
    }
    //取得值存放的区域
    int startx=0,starty=0,width=0;
    r=mySheet.get_Range(mySheet.Cells[1,2],mySheet.Cells[1,2]); 
    strValue=r.Value.ToString(); //清空存放参考数据的单元格
    mySheet.Cells[1,1]="";
    mySheet.Cells[1,2]=""; //根据信息分离出数据起始行、列、列数
    foreach(string str in strValue.Split(','))
    {
    if(starty==0)
    starty=System.Int32.Parse(str);
    else if(startx==0)
    startx=System.Int32.Parse(str);
    else if(width==0)
    width=System.Int32.Parse(str);

    }
    //将进度条×列数
    if(width>0)
    this.progressBar.Maximum=this.progressBar.Maximum*width; //隐藏统计文本,以便显示进度条
    this.txtCal.Visible=false;
    //逐步填写数据
    int i=0,j=0,ColCount=rpTable.Columns.Count,RowCount=rpTable.Rows.Count;
    object [,] objData = new object[RowCount+1,width];
    for(j=0;j<width;j++)
    {
    Application.DoEvents();
    //查找列名
    string colname="";
    r=mySheet.get_Range(mySheet.Cells[starty,startx+j],mySheet.Cells[starty,startx+j]);
    colname=r.Value.ToString().Trim();
    if(colname.Trim().Length==0)//空列名
    continue; //该列位于数据表中第几列
    int Col=-1;
    for(int k=0;k<ColCount;k++)
    {
    if(rpTable.Columns[k].Caption.Trim()==colname)//找到
    {
    Col=k;
    break;
    } } //对于没有的字段,置空
    if(Col==-1 || colname=="序号")
    {
    if(colname=="序号")
    {
    for(i=0;i<RowCount;i++)
    objData[i,j]=(i+1).ToString();
    }
    else
    {
    for(i=0;i<RowCount;i++)
    objData[i,j]="";
    }
    }
    else //找到
    {
    System.Type myType ;

    //测试数据类型
    myType=rpTable.Columns[colname].DataType;
    for(i=0;i<RowCount;i++)
    {
    //在进度条上显示出来
    if(this.progressBar.Value<this.progressBar.Maximum)
    this.progressBar.Value++; strValue="";
    if(rpTable==this.m_Table)
    strValue=this.dataGridInfo[i,Col].ToString().Trim();
    else
    strValue=rpTable.Rows[i][Col].ToString().Trim();
    //在明细窗口中做进一步处理
    strValue=this.m_DetailForm.ProValueForReport(colname,strValue);
    if(myType==typeof(Int32) || myType==typeof(Decimal)|| myType==typeof(float))
    {
    objData[i,j]=strValue;
    }
    //对于日期型,转换成符合中国习惯的形式
    else if(myType==typeof(System.DateTime))
    {
    DateTime dt;
    if(strValue.Length>0)
    {
    dt=DateTime.Parse(strValue);
    strValue=String.Format("{0}年{1}月{2}日",dt.Year,dt.Month,dt.Day);
    //如果有时分
    if(dt.Hour>0 || dt.Minute>0)
    {
    strValue+=String.Format(" {0}时{1}分",dt.Hour,dt.Minute);
    }
    }
    //myExcel.Cells[starty+i,startx+j]=strValue;
    objData[i,j]="'"+strValue;
    }
    else
    {
    //其他类型在前面加单引号,转换为文本,以防止诸如邮编之类的
    //被EXCEL认为数字而显示成科学型
    objData[i,j]="'"+strValue;
    }
    //显示进度
    if(this.progressBar.Value<this.progressBar.Maximum)
    this.progressBar.Value++; } //显示统计结果
    if(myType==typeof(Int32) || myType==typeof(Decimal)|| myType==typeof(float))
    {
    string exccelcolname=Tools.GetExcelColName(j+startx);
    string ss=string.Format("=sum({0}{1}:{0}{2})",exccelcolname,starty,i+starty-1);
    objData[i,j]=ss; }
    }
    }
    //填充数据
    r = mySheet.get_Range(mySheet.Cells[starty,startx],mySheet.Cells[starty,startx]);
    r = r.get_Resize(RowCount+1,width);
       r.Value = objData;
    //将选择的加上边框
    r=mySheet.get_Range(mySheet.Cells[starty,startx],mySheet.Cells[starty+RowCount,startx+width-1]);
    r.Select(); r.Borders[Excel.XlBordersIndex.xlDiagonalDown].LineStyle=(object)(-4142);
    r.Borders[Excel.XlBordersIndex.xlDiagonalUp].LineStyle=(object)(-4142); r.Borders[Excel.XlBordersIndex.xlEdgeLeft].LineStyle=(object)(1);
    r.Borders[Excel.XlBordersIndex.xlEdgeRight].LineStyle=(object)(1);
    r.Borders[Excel.XlBordersIndex.xlEdgeBottom].LineStyle=(object)(1);
    r.Borders[Excel.XlBordersIndex.xlEdgeTop].LineStyle=(object)(1);
    r.Borders[Excel.XlBordersIndex.xlInsideHorizontal].LineStyle=(object)(1);
    r.Borders[Excel.XlBordersIndex.xlInsideVertical].LineStyle=(object)(1);
    //在派生类中作进一步处理,如分类汇总等
    this.ShowFLW("正在进行后续处理,请等待……");
    this.m_DetailForm.AfterProExcel(p_TableName,starty,startx,width,mySheet,rpTable);
    myBook.Save();
    //通过选择一个单元格来去掉大面积的选择
    mySheet.get_Range(mySheet.Cells[1,1],mySheet.Cells[1,1]).Select();
    //将Excel显示出来
    myExcel.Visible=true;

    }
    catch(Exception ee)
    {
    MessageBox.Show(ee.Message);
    } //还原光标形状
    this.Cursor=System.Windows.Forms.Cursors.Default;
    this.progressBar.Value=1;
    //显示统计框
    this.txtCal.Visible=true;
    this.HideFLW();
    }
      

  8.   

    我的意思是End-User最终用户不用通过软件开发商,自己来设计自己的报表