实现Excel 表格功能的ActiveReports动态报表

注:此文本人是用Windows Live Writer 离线写的,没想到发布到CSDN后格式完全变了! 晕! 如有疑问的请联系. 另现求源代码的朋友不好意思了, 这个组件现在是商业软件的一部分, 恕不能提供.

动态报表DLL名: DynamicReportBuilder

类成员:

Members

主框架:

Diagram

目的:

完全实现Excel的丰富动态报表功能! 不再需要内置报表模板到程序.

开发语言: C#

引用组件:

  1. ActiveReports 3;
  2. 为了广泛支持更多的网格视图控件,本项目未引用除ActiveReports以外的任何第三方组件。

功能描述:

  1. 支持由任何数据结构对象(如:DataGridView; DevExpress.GridControl,DataTable...)构建报头字段;
  2. 支持自定义报表标题(TitleText),子标题(SubTitleText);
  3. 支持自定义分组(GroupHeader),并实现分组层级(GroupLevel).支持分组段尾(GroupFooter),页脚统计(PageFooter);
  4. 支持自定义字段的位置排序、字段标头宽度、颜色等设置;
  5. 动态报表中的各列(ReportField)自动匹配纸张宽度;
  6. 支持动态报表条件样式(FormatsCondition), 现在可以在报表预览窗口自定义创建条件样式了(v1.1)!
  7. 支持自定义打印机页面设置,字体,
  8. 支持ParentBanded固定带宽栏;
  9. 支持另存为项目模板文件。
  10. 已实现主从表的动态报表, 并提供了自己实现的表头数据源设计器(v1.1);

待完善:

  1. 目前调整字段顺序的方式为:双击字段项向下,按下CTRL键双击字段项则向上。这种功能是常用的,但目前没有提供比较好的显式操作方式,故需再改进报表配置器UI。

动态报表配置器主界面(失真的GIF动画):

 DynamicRD

源代码:

using System;
using System.Drawing;
using System.Text;

namespace CIMS.Report.Center.Builder
{
    public class ReportField:IDisposable
    {
        protected ReportFieldCollectionBase m_collection = null;
        protected FieldAppearance m_appearance = null;
        protected FieldBehavior m_behavior = null;

        protected string m_caption = string.Empty;
        protected string m_dataField = string.Empty;
        protected Type m_dataType;

        protected float m_width = 0;
        protected string m_outputFormat = string.Empty;
        protected object m_tag = null;
        protected int m_index = 0;
        protected bool m_visible = true;
        protected ReportField m_banded = null;

        public event EventHandler FieldVisibleChanged = null;
        public event EventHandler FieldCaptionChanged = null;
        public event EventHandler FieldWidthChanged = null;
        public event FieldIndexChangedHandler FieldIndexChanged = null;

        public ReportField(ReportFieldCollectionBase collection) : this(collection, string.Empty, string.Empty, 0, true) { }
        public ReportField(ReportFieldCollectionBase collection, string dataField) : this(collection, dataField, dataField, 0, true) { }
        public ReportField(ReportFieldCollectionBase collection, string caption, string dataField) : this(collection, caption, dataField, 0, true) { }
        public ReportField(ReportFieldCollectionBase collection, string caption, string dataField, float width) : this(collection,caption, dataField, width, true) { }

        public ReportField(ReportFieldCollectionBase collection, string caption, string dataField, float width, bool visible)
        {
 m_collection = collection;
            m_caption = caption;
            m_dataField = dataField;
            m_width = width;
            m_visible = visible;

            m_appearance = new FieldAppearance();
            m_behavior = new FieldBehavior();
        }

        #region Properties
        /// <summary>
        /// 获取当前字段的集合
        /// </summary>
        public ReportFieldCollectionBase Collection { get { return m_collection; } }
        /// <summary>
        /// 获取或设置 当前字段的所属固定带(没有即为Nothing)
        /// </summary>
        public ReportField ParentBanded { get { return m_banded; } set { m_banded = value; } }
        /// <summary>
        /// 获取列效果设置对象
        /// </summary>
        public FieldAppearance Appearance { get { return m_appearance; } }
        /// <summary>
        /// 获取列行为设置对象
        /// </summary>
        public FieldBehavior Behavior { get { return m_behavior; } }
        /// <summary>
        /// 获取或设置行标题文本
        /// </summary>
        public string Caption { get { return m_caption; } set { if (m_caption == value)return;
            m_caption = value;
            if (FieldCaptionChanged != null && this.IsLock == false) FieldCaptionChanged(this, EventArgs.Empty);
        } }

        protected bool IsLock { get {
            if (m_collection is ReportFieldCollection) return ((ReportFieldCollection)this.Collection).IsLock;
            return false;
        } }
        /// <summary>
        /// 获取或设置绑定到报表控件的数据字段名
        /// </summary>
        public string DataField { get { return m_dataField; } set { m_dataField = value; } }
        /// <summary>
        /// 获取或设置绑定字段的数据类型.在生成报表时,根据此类型属性决定创建合适的控件类型
        /// </summary>
        public Type DataType { get { return m_dataType; } set { m_dataType = value; } }
        /// <summary>
        /// 获取或设置列的初始宽度
        /// </summary>
        public float Width { get { if (this.Visible == false)return 0; return m_width; } set {
            if (m_width == value) return;

            m_width = value;
            if (FieldWidthChanged != null && this.IsLock==false) FieldWidthChanged(this, EventArgs.Empty);
        } }
        /// <summary>
        /// 获取或设置列输出文本的格式化字符格式
        /// </summary>
        public string OutputFormat { get { return m_outputFormat; } set { m_outputFormat = value; } }
        /// <summary>
        /// 获取或设置列的用户数据对象
        /// </summary>
        public object Tag { get { return m_tag; } set { m_tag = value; } }
        /// <summary>
        /// 获取或设置位置索引
        /// </summary>
        public int Index
        {
            get { if (this.Visible == false)return -1; return m_index; }
            set
            {
                if (m_index == value) return;
                int oldIndex=m_index;
                m_index = value;
                if (FieldIndexChanged != null && this.IsLock == false) FieldIndexChanged(this, new FieldIndexChangedArgs(m_index, oldIndex));
            }
        }
        /// <summary>
        /// 获取或设置是否创建到报表对象(在报表中是否可见)
        /// </summary>
        public bool Visible
        {
            get { return m_visible; }
            set
            {
                if (m_visible == value) return;
                m_visible = value;
                if (FieldVisibleChanged != null && this.IsLock == false) FieldVisibleChanged(this, EventArgs.Empty);
            }
        }
      
        #endregion

        public override bool Equals(object obj)
        {
            if (obj is ReportField) return ((ReportField)obj).DataField == this.DataField;
            if (obj != null) return obj.ToString() == this.ToString();

            return base.Equals(obj);
        }

        public override string ToString()
        {
            return this.DataField;
        }


        #region IDisposable 成员

        public void Dispose()
        {
            this.Appearance.Dispose();
        }

        #endregion
    }
}


……由于源代码太多! 下面只贴核心代码.

下面是配置器UI的核心代码…

下面是动态报表的核心实现部分(ReportBuilderBase,ReportBuilder,DetailReportBuilder待实现 )…

我们先来了解一下纸张布局.

PaperLayout

  1. 用于装订的装订线边距(固定区域);
  2. 上边距区域(相当于页眉);
  3. 打印区域(可通过调整页边距来打印更多内容!);
  4. 左右对开页的对称页边距;
  5. 下边距区域(相当于页脚)。
  6. 动态报表需要使各列按纸张打印区域自动调整宽度缩放比例,以不能产生空白区域或超出打印区域。下面是关键属性/函数:
  7. 由于ActiveReports默认使用的是英制单位,所以我们需要知道:1英寸=1/100像素。

///
/// 可放置控件的总宽度
///
protected float PrintWidth { get { return m_printWidth; } }

///
/// 控件的宽度缩放比例
///
protected float PrintWidthScale { get { return m_printWidthScale; } }

m_printWidth 和 m_printWidthScale 变量在BeginBuild(ActiveReport3 rpt)方法中初始化:

protected



virtual


void


BeginBuild(ActiveReport3 rpt)



{



//......更多初始化代码



m_defaultHeight = DesignOptions.DefaultPageDetailByNewReport;



m_hasBandeds = this


.Fields.HasBandedColumns;







m_printWidth = RoundTowDecimals(Settings.CalcPaperValidWidth(rpt.PageSettings));//打印空间宽度






if


(m_printWidth == -1) m_printWidth = DesignOptions.DefaultPrintWidthByNewReport;//默认宽度










m_printWidthScale = this


.Settings.AutoScaleFieldsSizeByPaperSpace ? CalcSacleWidth(m_printWidth) : 1;



}



protected



SizeF GetFieldSize(ReportField field, bool


fixFieldHeight)



{



return


GetFieldSize(field, fixFieldHeight, this


.DefaultHeight);



}



protected


SizeF GetFieldSize(ReportField field, float


customHeight)



{



return


GetFieldSize(field, false


, customHeight);



}



protected


SizeF GetFieldSize(ReportField field, bool


fixFieldHeight,float


fixHeight)



{



return


new


SizeF(RoundTowDecimals(CalcInchByFontSize(field.Width) * PrintWidthScale), fixFieldHeight ? fixHeight : (this


.HasBandeds && field.ParentBanded == null


? fixHeight * 2 : fixHeight));



}



///






/// 按文本和字体获取控件的大小,不适合于字段






///






///


文本







///


字体







///


是否返回字体高度,否则返回默认高度







///






protected


SizeF GetSize(string


text, Font font, bool


customHeight)



{



Graphics g = Owner.CreateGraphics();



using


(g)



{



SizeF result = g.MeasureString(text, font);







return


new


SizeF(RoundTowDecimals(CalcInchByFontSize(result.Width) * PrintWidthScale), (customHeight ? ConvertToInch(result.Height) : this


.DefaultHeight));



}



}



///






/// 计算固定带宽的总宽度






///






///


字段的固定带宽







///






public


SizeF GetBandedSize(ReportField banded)



{



float


totalWidth = 0;



foreach


(ReportField field in


this


.Fields)



{



if


(field.ParentBanded.Equals(banded)) totalWidth += GetFieldSize(field,true


).Width;



}



return


new


SizeF(totalWidth,this


.DefaultHeight);



}







public


float


CalcSacleWidth(float


printWidth)



{



float


totalWidth = 0;



foreach


(ReportField field in


this


.Fields)



{



if


(field.Visible == false


) continue


;







totalWidth += field.Width;



}







if


(Groups != null


)



{



int


count = Groups.VisibleCount;



if


(count > 1) totalWidth += (count - 1) * (DEFAULT_GROUP_LEFT * 100);



}







float


result =printWidth / ConvertToInch(totalWidth);











if


(result < 0) result = 1;



return


result;



}







public


static


float


RoundTowDecimals(float


value


)



{



return


(float


)(decimal


.Round((decimal


)value


, DEFAULT_ROUND_DECIMALS, MidpointRounding.AwayFromZero));



}







///






/// 将像素转到到英寸






///






///


像素







///






public


float


ConvertToInch(float


fieldDPI)



{



return


fieldDPI / 100;



}



///






/// 计算字段的实际宽度(英寸,不应用缩放比例)






///






///


像素







///






protected


float


CalcInchByFontSize(float


fieldDPI)



{



float


inchWidth = ConvertToInch(fieldDPI );







float


multiple = 0;



if


(this


.Settings.ReportFont.Size >= 11) multiple = 0.5f;



else


if


(this


.Settings.ReportFont.Size >= 10) multiple = 0.2f;



else


if


(this


.Settings.ReportFont.Size >= 9) multiple = 0.1f;







return


inchWidth + (inchWidth * multiple);







}



 

代码太多!只贴核心方法,需要完整代码的请联系







CreateDynamicReport CoreSourceCode








带分组段落和条件格式的动态报表:

Demo1

带固定带宽和条件格式及页脚统计的动态报表:

Demo2

v1.1 新增功能:

1, 现在能创建主从动态报表了!

2, 新增表头数据项目设计器以更好的支持主从报表的动态创建:

3, 新增一个报表生成向导, 从UI来看, WPF技术带来的UI视觉效果果然非同一般!

4, 新增水印设计器:

v1.1 增强功能和修改:

1, 现在Form支持调整大小了!

2, 现在报表支持动态图章和水印了!

猜你喜欢

转载自blog.csdn.net/3tzjq/article/details/4912759
今日推荐