网页WEB打印控件制作
在WEB系统中,打印的确是比较烦人的问题,如果我们能制作一个属于自己的自定义的打印插件,那么我们在后续自定义打印的时候能随心所欲的控制打印,这样的效果对于程序员来说是非常开心的一件事件,本文将自己开发编写的C# 制作的HTML打印插件分享出来,让有同样需求的朋友提供一个参考;此插件是基于Microsoft .NET Framework 2.0 开发的,缺点是每台客户端在安装插件时,必须要安装Microsoft .NET Framework 2.0 ;本插件能实现 页眉、页脚、表头、标题、表尾的分页打印;支持纸张类型、自动补充空行等功能;由于技术有限,肯定有很多不足的地方,请批评指正!
由于本打印插件是基于我们开发平台的报表基础来开发设计的,所以打印控件的原理:通过JS将页面表格数据生成固定格式的XML字符串(图片通过64base图片格式)传送给打印插件,有打印插件自主绘图生成打印页面。E_Print插件可以在WEB或WinForm中使用:
打印插件完整源码:E_Print.rar (包含插件源码、打包程序、winform调试DEMO)
下面贴出源码:(在源码中有详细的注释说明)
1、PrintControl 打印插件类
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Drawing.Printing; using System.Xml; using System.Security; using System.Drawing.DrawingD; using System.Drawing.Text; using System.Text.RegularExpressions; namespace E_Print { /// <summary> /// 打印控件 /// 实现IObjectSafety接口 /// 网页上所有所使用到的GUID 通过Guid工具生成的唯一编码 /// DEDD-BA--A-FFBEEC 编码以后不允许修改 /// </summary> [Guid("DEDD-BA--A-FFBEEC"), ProgId("EReportPrint"), ComVisible(true)] public partial class PrintControl : UserControl, IObjectSafety { #region 私有变量 #region 通用参数 /// <summary> /// 缩放比例 /// </summary> private float Zoom = ; /// <summary> /// 网页高度 像素 px /// </summary> private float HtmlHeight = ; /// <summary> /// 网页宽度 像素 px /// </summary> private float HtmlWidth = ; /// <summary> /// 报表区域矩形 /// </summary> private RectangleF TableRect = new RectangleF(); /// <summary> /// 报表绘制实例 /// </summary> private ReportDraw RptDraw = new ReportDraw(); #endregion #region 页边距 /// <summary> /// 左边距 /// 毫米 mm(一位小数) /// </summary> private float _marginLeft = .f; /// <summary> /// 右边距 /// </summary> private float _marginRight = .f; /// <summary> /// 上边距 /// </summary> private float _marginTop = .f; /// <summary> /// 下边距 /// </summary> private float _marginBottom = .f; #endregion #region 版型方向 /// <summary> /// 版型方向 Landscape: true 横向;false 纵向 /// </summary> private bool _landscape = false; #endregion #region 纸型大小 /// <summary> /// 纸张类型 /// </summary> private string _paperName = "A"; /// <summary> /// 纸张宽度 /// </summary> private int _paperWidth = ; // 毫米 /// <summary> /// 纸张高度 /// </summary> private int _paperHeight = ; // 毫米 #endregion #region 打印参数 /// <summary> /// 自适应纸张大小方法 /// null: 无 /// row: 横向 /// col: 纵向 /// </summary> private string _zoomType = "null"; /// <summary> /// 是否每页打印标题 /// </summary> private bool _isTblTitleAllPage = false; /// <summary> /// 是否每页打印表头 /// </summary> private bool _isTblHeadAllPage = false; /// <summary> /// 是否每页打印表尾 /// </summary> private bool _isTblFootAllPage = false; /// <summary> /// 最后一页自动补行 /// </summary> private bool _isAutoFillRow = false; /// <summary> /// 字符溢出是否换行缩小处理方式 /// </summary> private bool _isOverFlow = false; /// <summary> /// 打印数据 /// </summary> private string _dataXml = ""; #endregion #region 页眉参数 /// <summary> /// 页眉--绘制页眉 /// </summary> private bool _headDraw = false; /// <summary> /// 页眉--高度 毫米 /// 默认 刚好 /// </summary> private float _headHeight = .f; /// <summary> /// 页眉--左侧文字 /// </summary> private string _headLeft = ""; /// <summary> /// 页眉--中间文字 /// </summary> private string _headCenter = ""; /// <summary> /// 页眉--右侧文字 /// </summary> private string _headRight = ""; /// <summary> /// 页眉--字体名称 /// </summary> private string _headFontName = "宋体"; /// <summary> /// 页眉--字体大小 /// </summary> private string _headFontSize = "pt"; /// <summary> /// 页眉--字体颜色 /// </summary> private string _headFontColor = "Black"; /// <summary> /// 页眉--字体--粗体 /// </summary> private bool _headFontBold = false; /// <summary> /// 页眉--字体--斜体 /// </summary> private bool _headFontItalic = false; /// <summary> /// 页眉--字体--删除线 /// </summary> private bool _headFontStrikeout = false; /// <summary> /// 页眉--字体--下划线 /// </summary> private bool _headFontUnderline = false; /// <summary> /// 页眉--绘制分隔线 /// </summary> private bool _headLineDraw = false; /// <summary> /// 页眉--分隔线宽度 /// </summary> private float _headLineWidth = .f; /// <summary> /// 页眉--分隔线线型 /// </summary> private string _headLineDash = "solid"; /// <summary> /// 页眉--分隔线颜色 /// </summary> private string _headLineColor = "Black"; #endregion #region 页脚参数 /// <summary> /// 页脚--绘制页脚 /// </summary> private bool _footDraw = false; /// <summary> /// 页脚--高度 毫米 /// </summary> private float _footHeight = .f; /// <summary> /// 页脚--左侧文字 /// </summary> private string _footLeft = ""; /// <summary> /// 页脚--中间文字 /// </summary> private string _footCenter = ""; /// <summary> /// 页脚--右侧文字 /// </summary> private string _footRight = ""; /// <summary> /// 页脚--字体名称 /// </summary> private string _footFontName = "宋体"; /// <summary> /// 页脚--字体大小 /// </summary> private string _footFontSize = "pt"; /// <summary> /// 页脚--字体颜色 /// </summary> private string _footFontColor = "Black"; /// <summary> /// 页脚--字体--粗体 /// </summary> private bool _footFontBold = false; /// <summary> /// 页脚--字体--斜体 /// </summary> private bool _footFontItalic = false; /// <summary> /// 页脚--字体--删除线 /// </summary> private bool _footFontStrikeout = false; /// <summary> /// 页脚--字体--下划线 /// </summary> private bool _footFontUnderline = false; /// <summary> /// 页脚--绘制分隔线 /// </summary> private bool _footLineDraw = false; /// <summary> /// 页脚--分隔线宽度 /// </summary> private float _footLineWidth = .f; /// <summary> /// 页脚--分隔线线型 /// </summary> private string _footLineDash = "solid"; /// <summary> /// 页脚--分隔线颜色 /// </summary> private string _footLineColor = "Black"; #endregion #endregion #region 构造方法 /// <summary> /// 打印控件构造函数 /// </summary> public PrintControl() { InitializeComponent(); Init_PageSetting(); } #endregion #region 接口实现 private const string _IID_IDispatch = "{---C-}"; private const string _IID_IDispatchEx = "{aef-c-d--acdcaa}"; private const string _IID_IPersistStorage = "{A---C-}"; private const string _IID_IPersistStream = "{---C-}"; private const string _IID_IPersistPropertyBag = "{DF-CB-CE--AABB}"; private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = x; private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = x; private const int S_OK = ; private const int E_FAIL = unchecked((int)x); private const int E_NOINTERFACE = unchecked((int)x); private bool _fSafeForScripting = true; private bool _fSafeForInitializing = true; public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions) { int Rslt = E_FAIL; string strGUID = riid.ToString("B"); pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; switch (strGUID) { case _IID_IDispatch: case _IID_IDispatchEx: Rslt = S_OK; pdwEnabledOptions = ; if (_fSafeForScripting == true) pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; break; case _IID_IPersistStorage: case _IID_IPersistStream: case _IID_IPersistPropertyBag: Rslt = S_OK; pdwEnabledOptions = ; if (_fSafeForInitializing == true) pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA; break; default: Rslt = E_NOINTERFACE; break; } return Rslt; } public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions) { int Rslt = E_FAIL; string strGUID = riid.ToString("B"); switch (strGUID) { case _IID_IDispatch: case _IID_IDispatchEx: if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true)) Rslt = S_OK; break; case _IID_IPersistStorage: case _IID_IPersistStream: case _IID_IPersistPropertyBag: if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true)) Rslt = S_OK; break; default: Rslt = E_NOINTERFACE; break; } return Rslt; } #endregion #region 属性方法 #region 页边距 /// <summary> /// 获取--设置--左边距 /// 计量单位 毫米(mm) /// </summary> public float MARGINLEFT { get { return _marginLeft; } set { _marginLeft = value; } } /// <summary> /// 获取--设置--右边距 /// 计量单位 毫米(mm) /// </summary> public float MARGINRIGHT { get { return _marginRight; } set { _marginRight = value; } } /// <summary> /// 获取--设置--上边距 /// 计量单位 毫米(mm) /// </summary> public float MARGINTOP { get { return _marginTop; } set { _marginTop = value; } } /// <summary> /// 获取--设置--下边距 /// 计量单位 毫米(mm) /// </summary> public float MARGINBOTTOM { get { return _marginBottom; } set { _marginBottom = value; } } #endregion #region 版型方向 /// <summary> /// 获取--设置--版型方向 /// Landscape: true 横向; false 纵向 /// </summary> public bool LANDSCAPE { get { return _landscape; } set { _landscape = value; } } #endregion #region 纸张属性 /// <summary> /// 获取--设置--纸张类型 /// </summary> public string PAPERNAME { get { return _paperName; } set { _paperName = value; } } /// <summary> /// 获取--设置--纸张高度 /// 计量单位 毫米(mm) /// </summary> public int PAPERHEIGHT { get { return _paperHeight; } set { _paperHeight = value; } } /// <summary> /// 获取--设置--纸张宽度 /// 计量单位 毫米(mm) /// </summary> public int PAPERWIDTH { get { return _paperWidth; } set { _paperWidth = value; } } #endregion #region 页眉参数 /// <summary> /// 获取--设置--页眉是否绘制 /// </summary> public bool HEADDRAW { get { return _headDraw; } set { _headDraw = value; } } /// <summary> /// 获取--设置--页眉高度 /// 单位:毫米整数类型 /// </summary> public float HEADHEIGHT { get { return _headHeight; } set { _headHeight = value; } } /// <summary> /// 获取--设置--页眉左侧文字 /// </summary> public string HEADLEFT { get { return _headLeft; } set { _headLeft = value; } } /// <summary> /// 获取--设置--页眉中间文字 /// </summary> public string HEADCENTER { get { return _headCenter; } set { _headCenter = value; } } /// <summary> /// 获取--设置--页眉右侧文字 /// </summary> public string HEADRIGHT { get { return _headRight; } set { _headRight = value; } } /// <summary> /// 获取--设置--页眉字体名称 /// </summary> public string HEADFONTNAME { get { return _headFontName; } set { _headFontName = value; } } /// <summary> /// 获取--设置--页眉字体大小 /// </summary> public string HEADFONTSIZE { get { return _headFontSize; } set { _headFontSize = value; } } /// <summary> /// 获取--设置--页眉字体颜色 /// </summary> public string HEADFONTCOLOR { get { return _headFontColor; } set { _headFontColor = value; } } /// <summary> /// 获取--设置--页眉字体--粗体 /// </summary> public bool HEADFONTBOLD { get { return _headFontBold; } set { _headFontBold = value; } } /// <summary> /// 获取--设置--页眉字体--斜体 /// </summary> public bool HEADFONTITALIC { get { return _headFontItalic; } set { _headFontItalic = value; } } /// <summary> /// 获取--设置--页眉字体--删除线 /// </summary> public bool HEADFONTSTRIKEOUT { get { return _headFontStrikeout; } set { _headFontStrikeout = value; } } /// <summary> /// 获取--设置--页眉字体--下划线 /// </summary> public bool HEADFONTUNDERLINE { get { return _headFontUnderline; } set { _headFontUnderline = value; } } /// <summary> /// 获取--设置--是否绘制分割线 /// </summary> public bool HEADLINEDRAW { get { return _headLineDraw; } set { _headLineDraw = value; } } /// <summary> /// 获取--设置--页眉分隔线宽度 /// </summary> public float HEADLINEWIDTH { get { return _headLineWidth; } set { _headLineWidth = value; } } /// <summary> /// 获取--设置--页眉分隔线线型 /// </summary> public string HEADLINEDASH { get { return _headLineDash; } set { _headLineDash = value; } } /// <summary> /// 获取--设置--页眉分隔线颜色 /// </summary> public string HEADLINECOLOR { get { return _headLineColor; } set { _headLineColor = value; } } #endregion #region 页脚参数 /// <summary> /// 获取--设置--页脚是否绘制 /// </summary> public bool FOOTDRAW { get { return _footDraw; } set { _footDraw = value; } } /// <summary> /// 获取--设置--页脚高度 /// 单位:毫米整数类型 /// </summary> public float FOOTHEIGHT { get { return _footHeight; } set { _footHeight = value; } } /// <summary> /// 获取--设置--页脚左侧文字 /// </summary> public string FOOTLEFT { get { return _footLeft; } set { _footLeft = value; } } /// <summary> /// 获取--设置--页脚中间文字 /// </summary> public string FOOTCENTER { get { return _footCenter; } set { _footCenter = value; } } /// <summary> /// 获取--设置--页脚右侧文字 /// </summary> public string FOOTRIGHT { get { return _footRight; } set { _footRight = value; } } /// <summary> /// 获取--设置--页脚字体名称 /// </summary> public string FOOTFONTNAME { get { return _footFontName; } set { _footFontName = value; } } /// <summary> /// 获取--设置--页脚字体大小 /// </summary> public string FOOTFONTSIZE { get { return _footFontSize; } set { _footFontSize = value; } } /// <summary> /// 获取--设置--页脚字体颜色 /// </summary> public string FOOTFONTCOLOR { get { return _footFontColor; } set { _footFontColor = value; } } /// <summary> /// 获取--设置--页脚字体--粗体 /// </summary> public bool FOOTFONTBOLD { get { return _footFontBold; } set { _footFontBold = value; } } /// <summary> /// 获取--设置--页脚字体--斜体 /// </summary> public bool FOOTFONTITALIC { get { return _footFontItalic; } set { _footFontItalic = value; } } /// <summary> /// 获取--设置--页脚字体--删除线 /// </summary> public bool FOOTFONTSTRIKEOUT { get { return _footFontStrikeout; } set { _footFontStrikeout = value; } } /// <summary> /// 获取--设置--页脚字体--下划线 /// </summary> public bool FOOTFONTUNDERLINE { get { return _footFontUnderline; } set { _footFontUnderline = value; } } /// <summary> /// 获取--设置--是否绘制分割线 /// </summary> public bool FOOTLINEDRAW { get { return _footLineDraw; } set { _footLineDraw = value; } } /// <summary> /// 获取--设置--页脚分隔线宽度 /// </summary> public float FOOTLINEWIDTH { get { return _footLineWidth; } set { _footLineWidth = value; } } /// <summary> /// 获取--设置--页脚分隔线线型 /// </summary> public string FOOTLINEDASH { get { return _footLineDash; } set { _footLineDash = value; } } /// <summary> /// 获取--设置--页脚分隔线颜色 /// </summary> public string FOOTLINECOLOR { get { return _footLineColor; } set { _footLineColor = value; } } #endregion #region 打印参数 /// <summary> /// 获取--设置--打印数据 /// 前台传入的XML格式的打印数据 /// </summary> public string DATAXML { get { return _dataXml; } set { _dataXml = value; } } /// <summary> /// 获取--设置--是否每页打印标题 /// </summary> public bool ISTBLTITLEALLPAGE { get { return _isTblTitleAllPage; } set { _isTblTitleAllPage = value; } } /// <summary> /// 获取--设置--是否每页打印表头 /// </summary> public bool ISTBLHEADALLPAGE { get { return _isTblHeadAllPage; } set { _isTblHeadAllPage = value; } } /// <summary> /// 获取--设置--是否每页打印表尾 /// </summary> public bool ISTBLFOOTALLPAGE { get { return _isTblFootAllPage; } set { _isTblFootAllPage = value; } } /// <summary> /// 获取--设置--末页自动补行 /// </summary> public bool ISAUTOFILLROW { get { return _isAutoFillRow; } set { _isAutoFillRow = value; } } /// <summary> /// 获取--设置--缩放方向 /// 参数:以下三种;默认null /// null: 无 /// row: 横向 /// col: 纵向 /// </summary> public string ZOOMTYPE { get { return _zoomType; } set { _zoomType = value; } } /// <summary> /// 获取--设置--字符溢出是否缩小换行处理方式 /// </summary> public bool ISOVERFLOW { get { return _isOverFlow; } set { _isOverFlow = value; } } #endregion #region 加载参数 /// <summary> /// 加载打印参数 /// </summary> public void INITPRINTPARAM() { Init_PageSetting(); } #endregion #endregion #region 加载事件 /// <summary> /// 初始化--页面设置参数 /// </summary> private void Init_PageSetting() { this.E_PrintDocument.DefaultPageSettings.Margins.Left = (int)Math.Round(MARGINLEFT * ); // 左边距 this.E_PrintDocument.DefaultPageSettings.Margins.Right = (int)Math.Round(MARGINRIGHT * ); // 右边距 this.E_PrintDocument.DefaultPageSettings.Margins.Top = (int)Math.Round(MARGINTOP * ); // 上边距 this.E_PrintDocument.DefaultPageSettings.Margins.Bottom = (int)Math.Round(MARGINBOTTOM * ); // 下边距 this.E_PrintDocument.PrinterSettings.Copies = ; // 打印份数 this.E_PrintDocument.DefaultPageSettings.Landscape = this.LANDSCAPE; // 版型方向 PaperSize size = GetPaperSize(PAPERNAME); // 纸张类型 if (size != null) this.E_PrintDocument.DefaultPageSettings.PaperSize = size; else this.E_PrintDocument.DefaultPageSettings.PaperSize = new PaperSize(this.PAPERNAME, (int)Math.Round(this.PAPERWIDTH / . * ), (int)Math.Round(this.PAPERHEIGHT / . * )); } /// <summary> /// 获取--纸张类型 /// </summary> /// <param name="paperName">纸张类型名称</param> /// <returns></returns> private PaperSize GetPaperSize(string paperName) { PaperSize paper = null; foreach (PaperSize ps in this.E_PrintDocument.PrinterSettings.PaperSizes) { if (ps.PaperName.ToLower() == paperName.ToLower()) // 检查打印机是否有指定的纸张类型 { paper = ps; break; } } return paper; } #endregion #region 打印事件 /// <summary> /// 直接打印 /// 此处加入了再次调用打印设置界面,因为用户可能需要选择那种打印机 /// </summary> /// <returns></returns> public string PRINT() { // 直接打印时,直接调用printDocument的Print()方法 // 因为用户可能在打印之前还要再更改打印设置所以需再次显示打印设置对话框 if (this.E_PrintDialog.ShowDialog() == DialogResult.OK) { try { this.Init_Printer(); this.E_PrintDocument.Print(); } catch (Exception ex) { this.E_PrintDocument.PrintController.OnEndPrint(this.E_PrintDocument, new PrintEventArgs()); return ex.Message.ToString(); } } return ""; } /// <summary> /// 打印预览 /// 将打印的数据进行预览 /// </summary> public string PREVIEW() { try { this.Init_Printer(); this.E_PrintPreviewDialog.ShowDialog(); } catch (Exception ex) { return ex.Message.ToString(); } return ""; } /// <summary> /// 页面设置 /// 设置打印的页面的纸张大小、纸型、页面边距 /// </summary> public void PAGESTE() { // 页面设置对话框中使用的是公制长度计量单位 (厘米) // 在.net中采用的是英制的计量单位 (英寸) // 英寸约等于.厘米,厘米=毫米 // 所以在下面中需要加入转换信息 将对话框中设置的页边距进行转换保存 // 设置传入的纸张信息 if (this.E_PageSetupDialog.ShowDialog() == DialogResult.OK) // 弹出页面设置对话框 { if (System.Globalization.RegionInfo.CurrentRegion.IsMetric) // 转换页边距计量单位 this.E_PageSetupDialog.PageSettings.Margins = PrinterUnitConvert.Convert(this.E_PageSetupDialog.PageSettings.Margins, PrinterUnit.Display, PrinterUnit.TenthsOfAMillimeter); this.E_PrintDocument.DefaultPageSettings = this.E_PageSetupDialog.PageSettings; // 更新页面设置参数值 // 更新参数 this.LANDSCAPE = this.E_PrintDocument.DefaultPageSettings.Landscape; // 版型方向 this.PAPERNAME = this.E_PrintDocument.DefaultPageSettings.PaperSize.PaperName; // 纸张类型 PaperSize tmPSize = this.E_PrintDocument.DefaultPageSettings.PaperSize; // 纸张尺寸 this.PAPERWIDTH = (int)Math.Round(tmPSize.Width * . / ); // 纸张宽度 this.PAPERHEIGHT = (int)Math.Round(tmPSize.Height * . / ); // 纸张高度 this.MARGINLEFT = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Left / f, ); // 左边距 this.MARGINRIGHT = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Right / f, ); // 右边距 this.MARGINTOP = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Top / f, ); // 上边距 this.MARGINBOTTOM = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Bottom / f, ); // 下边距 } } /// <summary> /// 打印设置 /// 设置打印机的信息(选择打印机、设置打印份数等信息) /// </summary> public void PRINTSET() { this.E_PrintDialog.ShowDialog(); } #endregion #region 绘制对象 /// <summary> /// 打印及打印前初始化数据 /// </summary> private void Init_Printer() { HtmlHeight = ; // 网页报表高度 HtmlWidth = ; // 网页报表宽度 CalcTableRect(); // 计算区域矩形 RptDraw = new ReportDraw(); // 报表绘制实例 RptDraw.IsAllPrintTitle = this._isTblTitleAllPage; // 每页打印标题 RptDraw.IsAllPrintHead = this._isTblHeadAllPage; // 每页打印表头 RptDraw.IsAllPrintFoot = this._isTblFootAllPage; // 每页打印表尾 RptDraw.IsAutoFillRow = this._isAutoFillRow; // 末页自动补行 RptDraw.IsOverFlow = this._isOverFlow; // 字符溢出缩小 RptDraw.ReptRect = TableRect; // 赋值报表矩形 if (!ParseXML()) return; // 解析报表数据 CalcReportZoom(); // 计算缩小比例 CalcZoomAllSize(); // 按比计算尺寸 RptDraw.Zoom = this.Zoom; // 赋值缩小比例 RptDraw.CalcPaging(); // 计算打印分页 } /// <summary> /// PrintDocument 对象打印绘制事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void E_PrintDoc_PrintPage(object sender, PrintPageEventArgs e) { Graphics g = e.Graphics; g.Clear(Color.White); DrawHeader(g); DrawFooter(g); if (RptDraw.DrawReport(g)) e.HasMorePages = true; else e.HasMorePages = false; } /// <summary> /// 绘制页眉 /// </summary> /// <param name="g">绘图对象</param> private void DrawHeader(Graphics g) { // 是否绘制 if (_headDraw) { // 页眉实例 PageHeader pgHeader = new PageHeader(); // 页眉矩形 RectangleF pgHeaderRect = new RectangleF(TableRect.X, // X 坐标 TableRect.Y - mmToPixel(_headHeight), // Y 坐标 TableRect.Width, // W 宽度 mmToPixel(_headHeight) // H 高度 ); // 页眉赋值 pgHeader.HeadRect = pgHeaderRect; pgHeader.StrLeft = ReplacePageNum(_headLeft); // 左侧文本 pgHeader.StrCenter = ReplacePageNum(_headCenter); // 中间文本 pgHeader.StrRight = ReplacePageNum(_headRight); // 右侧文本 FontStyle fontStyle = FontStyle.Regular; // 字体样式 if (_headFontBold) fontStyle |= FontStyle.Bold; if (_headFontItalic) fontStyle |= FontStyle.Italic; if (_headFontStrikeout) fontStyle |= FontStyle.Strikeout; if (_headFontUnderline) fontStyle |= FontStyle.Underline; pgHeader.StrFont = new Font(_headFontName, (float)Convert.ToDouble(_headFontSize.ToLower().Replace("px", "").Replace("pt", "")), fontStyle, GraphicsUnit.Point); pgHeader.StrColor = (Color)PrintTool.StrToColor(_headFontColor); if (_headLineDraw) // 绘制分割线 { pgHeader.LineDraw = _headLineDraw; pgHeader.LineWidth = _headLineWidth; pgHeader.LineColor = (Color)PrintTool.StrToColor(_headLineColor); pgHeader.LineDash = PrintTool.GetDashStyle(_headLineDash); } // 页眉绘制 pgHeader.Draw(g); } } /// <summary> /// 绘制页脚 /// </summary> /// <param name="g">绘图对象</param> private void DrawFooter(Graphics g) { // 是否绘制 if (_footDraw) { // 页脚实例 PageFooter pgFooter = new PageFooter(); // 页脚矩形 RectangleF pgFooterRect = new RectangleF(TableRect.X, // X 坐标 TableRect.Y + TableRect.Height, // Y 坐标 TableRect.Width, // W 宽度 mmToPixel(_footHeight) // H 高度 ); // 页脚赋值 pgFooter.FootRect = pgFooterRect; pgFooter.StrLeft = ReplacePageNum(_footLeft); // 左侧文本 pgFooter.StrCenter = ReplacePageNum(_footCenter); // 中间文本 pgFooter.StrRight = ReplacePageNum(_footRight); // 右侧文本 FontStyle fontStyle = FontStyle.Regular; // 字体样式 if (_footFontBold) fontStyle |= FontStyle.Bold; if (_footFontItalic) fontStyle |= FontStyle.Italic; if (_footFontStrikeout) fontStyle |= FontStyle.Strikeout; if (_footFontUnderline) fontStyle |= FontStyle.Underline; pgFooter.StrFont = new Font(_footFontName, (float)Convert.ToDouble(_footFontSize.ToLower().Replace("px", "").Replace("pt", "")), fontStyle, GraphicsUnit.Point); pgFooter.StrColor = (Color)PrintTool.StrToColor(_footFontColor); if (_footLineDraw) // 绘制分割线 { pgFooter.LineDraw = _footLineDraw; pgFooter.LineWidth = _footLineWidth; pgFooter.LineColor = (Color)PrintTool.StrToColor(_footLineColor); pgFooter.LineDash = PrintTool.GetDashStyle(_footLineDash); } // 页脚绘制 pgFooter.Draw(g); } } #endregion #region 辅助方法 /// <summary> /// 毫米 TO 像素 /// </summary> /// <param name="mmValue">毫米值</param> /// <returns></returns> public static float mmToPixel(float mmValue) //mmValue是毫米,厘米=毫米 { return (mmValue / .f * f); } /// <summary> /// 替换 当前页码、总共页数两个变量 /// </summary> /// <param name="str"></param> /// <returns></returns> private string ReplacePageNum(string str) { string retStr = ""; if (str == null || str.Trim() == "") return retStr; retStr = str; int t = ; while (t >= ) { t = retStr.IndexOf("[curpage]", StringComparison.OrdinalIgnoreCase); if (t >= ) { retStr = retStr.Substring(, t) + RptDraw.CurPageNum.ToString() + retStr.Substring(t + "[curpage]".Length); } } t = ; while (t >= ) { t = retStr.IndexOf("[allpage]", StringComparison.OrdinalIgnoreCase); if (t >= ) { retStr = retStr.Substring(, t) + RptDraw.AllPageNum.ToString() + retStr.Substring(t + "[allpage]".Length); } } return retStr; } /// <summary> /// 解析XML文件 /// </summary> /// <returns>返回成功与否</returns> private bool ParseXML() { if (this.DATAXML == null || this.DATAXML.Trim() == "") return false; XmlDataDocument xmlDoc = new XmlDataDocument(); try { xmlDoc.LoadXml(this.DATAXML); XmlNode rootNode = xmlDoc.DocumentElement; if (rootNode.ChildNodes.Count == ) return false; if (rootNode.ChildNodes[].Name.ToLower() != "table") return false; XmlNode tableNode = rootNode.ChildNodes[]; // 表格节点 HtmlHeight = float.Parse(tableNode.Attributes["height"].Value); HtmlWidth = float.Parse(tableNode.Attributes["width"].Value); int tmRowIndex = ; foreach (XmlNode trNode in tableNode.ChildNodes) { if (trNode.Name.ToLower() != "tr") continue; // 解析表格行 Row tmRow = new Row(); tmRow.RowIndex = tmRowIndex; tmRow.RowHeight = float.Parse(trNode.Attributes["height"].Value); tmRow.RowType = trNode.Attributes["rowtype"].Value.ToLower(); // 解析单元格 foreach (XmlNode tdNode in trNode.ChildNodes) { Cell tmCell = new Cell(); #region 合并\坐标\矩形 tmCell.RowSpan = Convert.ToInt(tdNode.Attributes["rowspan"].Value); tmCell.ColSpan = Convert.ToInt(tdNode.Attributes["colspan"].Value); tmCell.RowIndex = Convert.ToInt(tdNode.Attributes["r"].Value); tmCell.ColIndex = Convert.ToInt(tdNode.Attributes["c"].Value); tmCell.RectX = float.Parse(tdNode.Attributes["x"].Value); tmCell.RectY = float.Parse(tdNode.Attributes["y"].Value); tmCell.RectW = float.Parse(tdNode.Attributes["w"].Value); tmCell.RectH = float.Parse(tdNode.Attributes["h"].Value); #endregion #region 设置单元格字体 FontStyle tmStyle = new FontStyle(); tmStyle = FontStyle.Regular; if (tdNode.Attributes["italic"].Value.ToString() == "") tmStyle |= FontStyle.Italic; if (tdNode.Attributes["bold"].Value.ToString() == "") tmStyle |= FontStyle.Bold; if (tdNode.Attributes["strikeout"].Value.ToString() == "") tmStyle |= FontStyle.Strikeout; if (tdNode.Attributes["underline"].Value.ToString() == "") tmStyle |= FontStyle.Underline; tmCell.CellFont = new Font(tdNode.Attributes["fontname"].Value, float.Parse(tdNode.Attributes["fontsize"].Value.Replace("pt", "").Replace("px", "")), tmStyle, GraphicsUnit.Point); tmCell.FontColor = (Color)PrintTool.StrToColor(tdNode.Attributes["fontcolor"].Value); tmCell.BackColor = (Color)PrintTool.StrToColor(tdNode.Attributes["backcolor"].Value); StringFormat tmFormat = new StringFormat(); switch (tdNode.Attributes["align"].Value.ToLower()) // 水平对齐方式 { case "center": tmFormat.Alignment = StringAlignment.Center; break; case "right": tmFormat.Alignment = StringAlignment.Far; break; default: tmFormat.Alignment = StringAlignment.Near; break; } switch (tdNode.Attributes["valign"].Value.ToLower()) // 垂直对齐方式 { case "middle": tmFormat.LineAlignment = StringAlignment.Center; break; case "bottom": tmFormat.LineAlignment = StringAlignment.Far; break; default: tmFormat.LineAlignment = StringAlignment.Near; break; } tmCell.strFormat = tmFormat; #endregion #region 内嵌图片-属性 tmCell.IsImage = tdNode.Attributes["isimage"].Value.ToString() == "" ? true : false; if (tmCell.IsImage) tmCell.ImageUrl = tdNode.Attributes["imageurl"].Value; #endregion #region 单元格边框属性 // 左边框线 string tmVal = tdNode.Attributes["leftwidth"].Value; if (tmVal.IndexOf("px") >= ) { tmCell.LeftBorder = new BorderLine( float.Parse(tmVal.Replace("px", "")), (Color)PrintTool.StrToColor(tdNode.Attributes["leftcolor"].Value), PrintTool.GetDashStyle(tdNode.Attributes["leftdash"].Value) ); } // 上边框线 tmVal = tdNode.Attributes["topwidth"].Value; if (tmVal.IndexOf("px") >= ) { tmCell.TopBorder = new BorderLine( float.Parse(tmVal.Replace("px", "")), (Color)PrintTool.StrToColor(tdNode.Attributes["topcolor"].Value), PrintTool.GetDashStyle(tdNode.Attributes["topdash"].Value) ); } // 右边框线 tmVal = tdNode.Attributes["rightwidth"].Value; if (tmVal.IndexOf("px") >= ) { tmCell.RightBorder = new BorderLine( float.Parse(tmVal.Replace("px", "")), (Color)PrintTool.StrToColor(tdNode.Attributes["rightcolor"].Value), PrintTool.GetDashStyle(tdNode.Attributes["rightdash"].Value) ); } // 下边框线 tmVal = tdNode.Attributes["bottomwidth"].Value; if (tmVal.IndexOf("px") >= ) { tmCell.BottomBorder = new BorderLine( float.Parse(tmVal.Replace("px", "")), (Color)PrintTool.StrToColor(tdNode.Attributes["bottomcolor"].Value), PrintTool.GetDashStyle(tdNode.Attributes["bottomdash"].Value) ); } #endregion #region 单据格数据数值 tmCell.Value = tdNode.InnerText; #endregion // 加入对应的行内 tmRow.RowCells.Add(tmCell); } RptDraw.RowsList.Add(tmRow); tmRowIndex++; } } catch { return false; } finally { xmlDoc = null; } return true; } /// <summary> /// 计算报表区域矩形 /// 真实的绘制报表的区域 /// </summary> private void CalcTableRect() { // 重新初始化实例 TableRect = new RectangleF(); // 左顶点 X坐标 TableRect.X = mmToPixel(_marginLeft); // 左顶点 Y坐标 TableRect.Y = mmToPixel(_marginTop); if (_headDraw) // 需要绘制页眉 TableRect.Y += mmToPixel(_headHeight); // 报表矩形宽度高度 if (this.LANDSCAPE) // 版型方向 横向 { // 颠倒 宽高 TableRect.Width = mmToPixel((float)_paperHeight - _marginLeft - _marginRight); TableRect.Height = mmToPixel((float)_paperWidth - _marginTop - _marginBottom); } else // 版型方向 纵向 { TableRect.Width = mmToPixel((float)_paperWidth - _marginLeft - _marginRight); TableRect.Height = mmToPixel((float)_paperHeight - _marginTop - _marginBottom); } // 报表矩形高度缩减 if (_headDraw) // 需要绘制页眉 TableRect.Height -= mmToPixel(_headHeight); if (_footDraw) // 需要绘制页脚 TableRect.Height -= mmToPixel(_footHeight); } /// <summary> /// 计算缩放比例 /// </summary> private void CalcReportZoom() { if (this.ZOOMTYPE.ToLower() == "row") { if (Convert.ToInt(TableRect.Width) >= HtmlWidth) this.Zoom = ; else this.Zoom = TableRect.Width / HtmlWidth; } else if (this.ZOOMTYPE.ToLower() == "col") { if (Convert.ToInt(TableRect.Height) >= HtmlHeight) this.Zoom = ; else this.Zoom = TableRect.Height / HtmlHeight; } else { this.Zoom = ; } } /// <summary> /// 转换所有的尺寸 /// 根据缩放比例 /// </summary> private void CalcZoomAllSize() { if (this.Zoom != ) { // 转换HTML 高度宽度 HtmlWidth = HtmlWidth * Zoom; HtmlHeight = HtmlHeight * Zoom; // 转换所有行号 foreach (Row zRow in this.RptDraw.RowsList) { // 行高缩小 zRow.RowHeight = zRow.RowHeight * Zoom; // 转换所有单元格 foreach (Cell zCell in zRow.RowCells) { zCell.RectX = zCell.RectX * Zoom; zCell.RectY = zCell.RectY * Zoom; zCell.RectW = zCell.RectW * Zoom; zCell.RectH = zCell.RectH * Zoom; zCell.TopBorder.LineWidth = zCell.TopBorder.LineWidth * Zoom; zCell.BottomBorder.LineWidth = zCell.BottomBorder.LineWidth * Zoom; zCell.LeftBorder.LineWidth = zCell.LeftBorder.LineWidth * Zoom; zCell.RightBorder.LineWidth = zCell.RightBorder.LineWidth * Zoom; // 字体相应缩小 zCell.CellFont = new Font(zCell.CellFont.Name, zCell.CellFont.Size * Zoom, zCell.CellFont.Style, GraphicsUnit.Point); } } } } #endregion } }
2、ReportDraw 打印绘制类
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.DrawingD; using System.IO; namespace E_Print { /// <summary> /// 报表绘制 /// </summary> public class ReportDraw { #region 私有成员 /// <summary> /// 当前页码 /// </summary> private int _curPageNum; /// <summary> /// 总共页数 /// </summary> private int _allPageNum; /// <summary> /// 表格矩形 /// </summary> private RectangleF _reptRect; /// <summary> /// 报表全部行集 /// </summary> private List<Row> _rowsList; /// <summary> /// 分页页面数组 /// </summary> private List<PagingItem> _pageList; /// <summary> /// 是否每页打印标题 /// </summary> private bool _isAllPrintTitle; /// <summary> /// 是否每页打印表头 /// </summary> private bool _isAllPrintHead; /// <summary> /// 是否每页打印表尾 /// </summary> private bool _isAllPrintFoot; /// <summary> /// 是否末页自动补行 /// </summary> private bool _isAutoFillRow; /// <summary> /// 缩小比例 /// </summary> private float _zoom; /// <summary> /// 字符溢出处理方式 /// </summary> private bool _isOverFlow; /// <summary> /// 每页打印的标题+表头的高度 /// </summary> private float _headPix; /// <summary> /// 每页打印的表尾高度 /// </summary> private float _footPix; #endregion #region 构造方法 /// <summary> /// 构造函数 /// </summary> public ReportDraw() { _curPageNum = ; _allPageNum = ; _reptRect = new RectangleF(); _rowsList = new List<Row>(); _pageList = new List<PagingItem>(); _isAllPrintTitle = false; _isAllPrintHead = false; _isAllPrintFoot = false; _isAutoFillRow = false; _zoom = ; _isOverFlow = false; _headPix = ; _footPix = ; } /// <summary> /// 构造函数 /// </summary> /// <param name="printTitle">每页打印标题</param> /// <param name="printHead">每页打印表头</param> /// <param name="printFoot">每页打印表位</param> /// <param name="fillRows">自动补全空行</param> /// <param name="tableRect">报表尺寸矩形</param> /// <param name="overFlow">字符溢出处理</param> public ReportDraw(bool printTitle, bool printHead, bool printFoot, bool fillRows, RectangleF tableRect, bool overFlow) { _reptRect = tableRect; _isAllPrintTitle = printTitle; _isAllPrintHead = printHead; _isAllPrintFoot = printFoot; _isAutoFillRow = fillRows; _isOverFlow = overFlow; _curPageNum = ; _allPageNum = ; _zoom = ; _rowsList = new List<Row>(); _pageList = new List<PagingItem>(); _headPix = ; _footPix = ; } #endregion #region 属性方法 /// <summary> /// 获取--设置--当前页码 /// </summary> public int CurPageNum { get { return _curPageNum; } set { _curPageNum = value; } } /// <summary> /// 获取--设置--总共页数 /// </summary> public int AllPageNum { get { return _allPageNum; } set { _allPageNum = value; } } /// <summary> /// 获取--设置--表格矩形 /// </summary> public RectangleF ReptRect { get { return _reptRect; } set { _reptRect = value; } } /// <summary> /// 获取--设置--报表全部行集 /// </summary> public List<Row> RowsList { get { return _rowsList; } set { _rowsList = value; } } /// <summary> /// 获取--设置--分页页面数组 /// </summary> public List<PagingItem> PageList { get { return _pageList; } set { _pageList = value; } } /// <summary> /// 获取--设置--是否每页打印标题 /// </summary> public bool IsAllPrintTitle { get { return _isAllPrintTitle; } set { _isAllPrintTitle = value; } } /// <summary> /// 获取--设置--是否每页打印表头 /// </summary> public bool IsAllPrintHead { get { return _isAllPrintHead; } set { _isAllPrintHead = value; } } /// <summary> /// 获取--设置--是否每页打印表尾 /// </summary> public bool IsAllPrintFoot { get { return _isAllPrintFoot; } set { _isAllPrintFoot = value; } } /// <summary> /// 获取--设置--末页是否自动补行 /// </summary> public bool IsAutoFillRow { get { return _isAutoFillRow; } set { _isAutoFillRow = value; } } /// <summary> /// 获取--设置--缩小比例 /// </summary> public float Zoom { get { return _zoom; } set { _zoom = value; } } /// <summary> /// 获取--设置--字符溢出处理方式 /// </summary> public bool IsOverFlow { get { return _isOverFlow; } set { _isOverFlow = value; } } /// <summary> /// 获取--设置--每页打印的标题+表头高度 /// </summary> public float HeadPix { get { return _headPix; } set { _headPix = value; } } /// <summary> /// 获取--设置--每页打印的表尾高度 /// </summary> public float FootPix { get { return _footPix; } set { _footPix = value; } } #endregion #region 计算分页 /// <summary> /// 计算分页 /// </summary> public void CalcPaging() { // 分页实例 PagingCalc insCalc = new PagingCalc(); insCalc.TableRect = this.ReptRect; insCalc.RowsList = this.RowsList; insCalc.IsAllPrintTitle = this.IsAllPrintTitle; insCalc.IsAllPrintHead = this.IsAllPrintHead; insCalc.IsAllPrintFoot = this.IsAllPrintFoot; // 分页计算 _pageList = insCalc.CalcPages(); this._allPageNum = _pageList.Count; this._curPageNum = ; this._headPix = insCalc.MyHeadPix; this._footPix = insCalc.MyFootPix; } #endregion #region 绘制方法 /// <summary> /// 绘制报表 /// </summary> /// <param name="g"></param> /// <returns>返回是否结束</returns> public bool DrawReport(Graphics g) { bool isMorePage = false; float offsetX = _reptRect.X; // X 偏移量 float offsetY = _reptRect.Y; // Y 偏移量 bool isCanFillRow = false; // 是否需要补行 bool isFillFlag = false; // 是否已经补过 int isFillRowNum = ; // 需要补充几行 PagingItem nowPage = GetPageItem(CurPageNum); // 当前页 if (nowPage != null) { #region 判定高度不足是否自动补行 // 判定补行条件 报表设置了末页不足自动补行、同时 为最后一页 if (_isAutoFillRow == true && CurPageNum == AllPageNum) { // 判定页面高度 与 数据高度 float N_PageHeith = ReptRect.Height; // 当前页面高度 float N_DataHeith = GetThisPageDataRowsHeight(); // 当前数据高度 // 补行行高 while ((N_DataHeith + (isFillRowNum + ) * * Zoom) < N_PageHeith) { isFillRowNum++; } if (isFillRowNum > ) isCanFillRow = true; } #endregion #region 首先绘制上一页补充单元格 if (CurPageNum > ) { PagingItem prePage = GetPageItem(CurPageNum - ); // 上一页 if (prePage != null) { foreach (PagingMakeUp tmMk in prePage.MakeupList) { // 绘制补充单元格(上页中未绘制完成的单元格) DrawTD(g, tmMk.MakeupCell, offsetX, offsetY, true, tmMk.MakeupHeight, false); } } } #endregion #region 其次绘制当前页面的单元格 // 其次绘制当前页的单元格 for (int ii = ; ii < nowPage.IndexList.Count; ii++) { // 先绘制 TD CELL 单元格 Row rowTR = GetRow(nowPage.IndexList[ii]); #region 执行补行 if (isCanFillRow == true && rowTR.RowType.ToLower().Trim() == "f") // 需要补行 行标志为F 表尾前进行补充空行 { Row fillRow = new Row(); if (ii == ) fillRow = rowTR; else fillRow = GetRow(nowPage.IndexList[ii - ]); if (fillRow != null) // 绘制自动补充的空行单元格 { // 开始补充空行 for (int fi = ; fi <= isFillRowNum; fi++) { bool bcFlag = true; // 绘制单元格 foreach (Cell fillTdCell in fillRow.RowCells) { if (bcFlag) { // 绘制边框线(合并单元格的情况才用到) if (fillTdCell.RectX > ) { DrawLine(g, offsetX, offsetY, offsetX, offsetY + .F * Zoom); // 最左边竖线 DrawLine(g, offsetX, offsetY + .F * Zoom, offsetX + fillTdCell.RectX, offsetY + .F * Zoom); } bcFlag = false; } DrawTD(g, fillTdCell, offsetX, offsetY, false, , true); } // 再将偏移量+行号 补充的行高全部为px offsetY += * Zoom; } } isFillFlag = true; } #endregion #region 正常绘制 foreach (Cell td in rowTR.RowCells) { DrawTD(g, td, offsetX, offsetY, false, , false); } // 再将偏移量+行号 offsetY += rowTR.RowHeight; #endregion } // 判定是否补过;没有补充过,则在最后进行补充空行 if ((isCanFillRow == true) && (isFillFlag == false) && (nowPage.IndexList.Count > )) { Row fillRow = GetRow(nowPage.IndexList[nowPage.IndexList.Count - ]); if (fillRow != null) // 绘制自动补充的空行单元格 { // 开始补充空行 for (int fi = ; fi <= isFillRowNum; fi++) { bool newFlag = true; foreach (Cell fillTdCell in fillRow.RowCells) { if (newFlag) { // 绘制边框线(合并单元格的情况才用到) if (fillTdCell.RectX > ) { DrawLine(g, offsetX, offsetY, offsetX, offsetY + .F * Zoom); // 最左边竖线 DrawLine(g, offsetX, offsetY + .F * Zoom, offsetX + fillTdCell.RectX, offsetY + .F * Zoom); } newFlag = false; } DrawTD(g, fillTdCell, offsetX, offsetY, false, , true); } offsetY += * Zoom; // 再将偏移量+行号 补充的行高全部为px } } } #endregion if (CurPageNum < AllPageNum) { isMorePage = true; // 还有下页 CurPageNum++; // 页码增加 } } return isMorePage; } /// <summary> /// 绘制单元格 /// </summary> /// <param name="g">绘图对象</param> /// <param name="tdCell">单元格</param> /// <param name="setX">X偏移量</param> /// <param name="setY">Y坐标值</param> /// <param name="isMakeup">是否补充单元格</param> /// <param name="mkH">补充单元格高度</param> /// <param name="fillCell">自动补行的单元格</param> private void DrawTD(Graphics g, Cell tdCell, float setX, float setY, bool isMakeup, float mkH, bool fillCell) { #region 参数变量 Pen pen; Brush brush; // 获取单元格绘制坐标矩形信息 float tdX = tdCell.RectX + setX; float tdY = setY; float tdW = tdCell.RectW; float tdH = ; if (fillCell) { tdH = * Zoom; // 自动补行的单元格的高度固定为px } else { if (isMakeup) // 补充单元格 { tdH = mkH; tdY = tdY + HeadPix; // 如果是补充单元格,则此单元格的Y坐标:如果每页打印标题或表头,则Y坐标 需要下移 HeadPix } else // 实际单元格 { tdH = tdCell.RectH; } if (tdCell.RowSpan > ) // 判定单元格高度是否超过底线 { tdH = Calc_CellOverHeight(tdCell, tdY, tdH); } } #endregion #region 绘制背景 // 填充颜色 brush = new SolidBrush(tdCell.BackColor); g.FillRectangle(brush, tdX + .f * Zoom, tdY + .f * Zoom, tdW - .f * Zoom, tdH - .f * Zoom); #endregion #region 绘制边框 // 左边框线 if (tdCell.LeftBorder.LineWidth > ) { pen = new Pen(tdCell.LeftBorder.LineColor); pen.DashStyle = tdCell.LeftBorder.LineDash; pen.Width = tdCell.LeftBorder.LineWidth; g.DrawLine(pen, tdX, tdY, tdX, tdY + tdH); } // 上边框线 if (tdCell.TopBorder.LineWidth > ) { pen = new Pen(tdCell.TopBorder.LineColor); pen.DashStyle = tdCell.TopBorder.LineDash; pen.Width = tdCell.TopBorder.LineWidth; g.DrawLine(pen, tdX, tdY, tdX + tdW, tdY); } // 右边框线 if (tdCell.RightBorder.LineWidth > ) { pen = new Pen(tdCell.RightBorder.LineColor); pen.DashStyle = tdCell.RightBorder.LineDash; pen.Width = tdCell.RightBorder.LineWidth; g.DrawLine(pen, tdX + tdW, tdY, tdX + tdW, tdY + tdH); } // 下边框线 if (tdCell.BottomBorder.LineWidth > ) { pen = new Pen(tdCell.BottomBorder.LineColor); pen.DashStyle = tdCell.BottomBorder.LineDash; pen.Width = tdCell.BottomBorder.LineWidth; g.DrawLine(pen, tdX, tdY + tdH, tdX + tdW, tdY + tdH); } #endregion #region 绘制文字 if (!fillCell) { RectangleF rect = new RectangleF(tdX, tdY, tdW, tdH); if (tdCell.IsImage) { this.DrawImg(g, rect, tdCell.ImageUrl); } else { brush = new SolidBrush(tdCell.FontColor); this.DrawStr(g, rect, brush, tdCell.CellFont, tdCell.strFormat, tdCell.Value); } } #endregion } /// <summary> /// 绘制字符串 /// 溢出时,换行缩小字符 /// 字体缩小到的最小值不得小于 /// </summary> /// <param name="g">绘图对象</param> /// <param name="strRect">文本区域</param> /// <param name="strBrush">文本笔画</param> /// <param name="strFont">文本字体</param> /// <param name="strFormat">文本格式</param> /// <param name="strValue">文本字符</param> /// <returns></returns> private void DrawStr(Graphics g, RectangleF strRect, Brush strBrush, Font strFont, StringFormat strFormat, string strValue) { // 报表设置:字符溢出不做处理 if (!this.IsOverFlow) { g.DrawString(strValue, strFont, strBrush, strRect, strFormat); } else // 需要处理 { // 测量字体的宽度和高度 会发现误差很大,如果一个一个的测量,误差就实在太大,所以这里就用简单的方式来进行处理 SizeF sf = g.MeasureString(strValue, strFont); // 此种方式测量误差很大,如果 if (strRect.Width > sf.Width) { g.DrawString(strValue, strFont, strBrush, strRect, strFormat); } else { // 计算换行后字符的全部高度是否满足 int maxLines = ; // 计算当前字符当前字体最大打印的行数 maxLines = (int)Math.Ceiling((double)sf.Width / (double)strRect.Width); if (strRect.Height >= maxLines * sf.Height) { g.DrawString(strValue, strFont, strBrush, strRect, strFormat); } else { float tmScale = strRect.Height / (maxLines * sf.Height); Font tmNewFont = new Font(strFont.Name, strFont.Size * tmScale, strFont.Style, GraphicsUnit.Point); g.DrawString(strValue, tmNewFont, strBrush, strRect, strFormat); } } } } /// <summary> /// 绘制图片 /// 将Base图片流字符串转换成图片并进行绘制 /// </summary> /// <param name="g"></param> /// <param name="strRect"></param> /// <param name="baseImg"></param> private void DrawImg(Graphics g, RectangleF strRect, string baseImg) { if (baseImg.Trim() == "") return; string imgStr = baseImg.Replace("data:image/gif;base,", "").Trim(); if (imgStr == "") return; // 生成图片 try { MemoryStream stream = new MemoryStream(Convert.FromBaseString(imgStr)); Bitmap picImg = new Bitmap(stream); RectangleF imgRectF = new RectangleF(f, f, (float)picImg.Width, (float)picImg.Height); // 原始图片矩形 RectangleF newRectF = new RectangleF(strRect.X + f, strRect.Y + f, (float)strRect.Width - f, (float)strRect.Height - f); // 绘制图片矩形 g.DrawImage(picImg, newRectF, imgRectF, GraphicsUnit.Pixel); // 绘制缩放图片 stream.Close(); } catch { return; } } /// <summary> /// 绘制线条 /// </summary> /// <param name="g">绘图对象</param> /// <param name="start_X">开始X</param> /// <param name="start_Y">开始Y</param> /// <param name="end_X">结束X</param> /// <param name="end_Y">结束Y</param> private void DrawLine(Graphics g, float start_X, float start_Y, float end_X, float end_Y) { Pen linePen = new Pen(Color.Black, .f); linePen.DashStyle = DashStyle.Solid; g.DrawLine(linePen, start_X, start_Y, end_X, end_Y); } private float ChangeUnit(float vSize) { return (vSize * f / f * f / f); } /// <summary> /// 获取行对象 /// </summary> /// <param name="rowIndex"></param> /// <returns></returns> private Row GetRow(int rowIndex) { foreach (Row retRow in _rowsList) { if (retRow.RowIndex == rowIndex) return retRow; } return null; } /// <summary> /// 获取分页页面 /// </summary> /// <param name="pNo">页码</param> /// <returns></returns> private PagingItem GetPageItem(int pNo) { foreach (PagingItem retPItem in PageList) { if (retPItem.PageNum == pNo) return retPItem; } return null; } /// <summary> /// 计算绘制高度 /// 判定并且计算单元格高度是否超过当前页面所有行高度的底线 /// </summary> /// <param name="mCell">单元格</param> /// <param name="mY">Y 轴坐标值</param> /// <param name="mH">H 当前高度</param> /// <returns></returns> private float Calc_CellOverHeight(Cell mCell, float mY, float mH) { float returnHeight = ; // 返回高度 float tm_AllTrHeight = GetThisPageDataRowsHeight(); // 当前页面内所有数据行的高度 float tm_RealY = ; // 相对最大Y值 float tm_AbsY = ; // 实际最大Y值 float tm_OverPlus = ; // 单元格剩余高度 tm_RealY = mY + mH; // 实际最大Y值 if (IsAllPrintFoot) // 每页打印表尾 tm_AbsY = ReptRect.Y + (tm_AllTrHeight - FootPix); // 需要减去表尾高度 else tm_AbsY = tm_AllTrHeight + ReptRect.Y; if (tm_RealY > tm_AbsY) { returnHeight = tm_AbsY - mY; // 当前页面实际最大高度-单元格的当前Y坐标值 = 返回单元格在本页内需要绘制的高度 tm_OverPlus = mH - returnHeight; // 当前高度-单元格当前页面需要绘制的高度=下页需要绘制的补充高度 // 将当前单元格添加到后页需要补充绘制数组中去 PagingItem nPageItem = GetPageItem(CurPageNum); PagingMakeUp nMakeUp = new PagingMakeUp(); nMakeUp.MakeupCell = mCell; nMakeUp.MakeupHeight = tm_OverPlus; nPageItem.MakeupList.Add(nMakeUp); } else { returnHeight = mH; } return returnHeight; } /// <summary> /// 获取本页内所有数据行的高度 /// </summary> /// <returns></returns> private float GetThisPageDataRowsHeight() { float retHeight = ; PagingItem oThisPage = GetPageItem(CurPageNum); // 当前页 foreach (int oRowIndex in oThisPage.IndexList) { Row oThisRow = GetRow(oRowIndex); retHeight += oThisRow.RowHeight; } return retHeight; } /// <summary> /// 获取页内某一项所属行的高度 /// </summary> /// <param name="itemPage">页面对象</param> /// <param name="itemIndex">本页行数组中的某一项的序号</param> /// <returns></returns> private float GetThisPageOneRowHeight(PagingItem itemPage, int itemIndex) { float retHeight = ; if (itemIndex < itemPage.IndexList.Count && itemIndex >= ) { Row oThisRow = GetRow(itemPage.IndexList[itemIndex]); retHeight = oThisRow.RowHeight; } return retHeight; } #endregion } } 3、PagingCalc 分页计算类 using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace E_Print { /// <summary> /// 分页计算 /// </summary> public class PagingCalc { #region 私有变量 /// <summary> /// 表格区域 /// </summary> private RectangleF _tableRect; /// <summary> /// 报表行集 /// </summary> private List<Row> _rowsList; /// <summary> /// 是否每页打印标题 /// </summary> private bool _isAllPrintTitle; /// <summary> /// 是否每页打印表头 /// </summary> private bool _isAllPrintHead; /// <summary> /// 是否每页打印表尾 /// </summary> private bool _isAllPrintFoot; /// <summary> /// 标题行集 /// </summary> private List<Row> TitleList; /// <summary> /// 表头前行集 /// </summary> private List<Row> HForeList; /// <summary> /// 表头行集 /// </summary> private List<Row> HeadList; /// <summary> /// 数据行集 /// </summary> private List<Row> DataList; /// <summary> /// 表尾行集 /// </summary> private List<Row> FootList; /// <summary> /// 每页打印标题+表头高度 /// </summary> private float _myHeadPix; /// <summary> /// 每页打印表尾高度 /// </summary> private float _myFootPix; #endregion #region 构造方法 /// <summary> /// 构造函数 /// </summary> public PagingCalc() { _tableRect = new RectangleF(); _rowsList = new List<Row>(); _isAllPrintTitle = false; _isAllPrintHead = false; _isAllPrintFoot = false; TitleList = new List<Row>(); HForeList = new List<Row>(); HeadList = new List<Row>(); DataList = new List<Row>(); FootList = new List<Row>(); _myHeadPix = ; _myFootPix = ; } #endregion #region 属性方法 /// <summary> /// 获取--设置--表格区域 /// </summary> public RectangleF TableRect { get { return _tableRect; } set { _tableRect = value; } } /// <summary> /// 获取--设置--表格行集 /// </summary> public List<Row> RowsList { get { return _rowsList; } set { _rowsList = value; } } /// <summary> /// 获取--设置--是否每页打印标题 /// </summary> public bool IsAllPrintTitle { get { return _isAllPrintTitle; } set { _isAllPrintTitle = value; } } /// <summary> /// 获取--设置--是否每页打印表头 /// </summary> public bool IsAllPrintHead { get { return _isAllPrintHead; } set { _isAllPrintHead = value; } } /// <summary> /// 获取--设置--是否每页打印表尾 /// </summary> public bool IsAllPrintFoot { get { return _isAllPrintFoot; } set { _isAllPrintFoot = value; } } /// <summary> /// 获取--设置--每页打印标题+表头高度 /// </summary> public float MyHeadPix { get { return _myHeadPix; } set { _myHeadPix = value; } } /// <summary> /// 获取--设置--每页打印表尾巴高度 /// </summary> public float MyFootPix { get { return _myFootPix; } set { _myFootPix = value; } } #endregion #region 计算方法 /// <summary> /// 分页计算 /// </summary> /// <returns></returns> public List<PagingItem> CalcPages() { List<PagingItem> retPages = new List<PagingItem>(); // 无需分页 if (Get_TableAllHeight() <= TableRect.Height) { PagingItem tmItem = new PagingItem(); tmItem.PageNum = ; for (int y = ; y < RowsList.Count; y++) { tmItem.IndexList.Add(y); } retPages.Add(tmItem); } else // 需要分页 { // 有设置了 每页打印标题、表头、表位 其中的任意一个 if (Get_IsCusSet_THDF()) // 则执行每页相对分页 { Paging_Relative(, ref retPages); // 计算每页打印头尾高度 MyHeadPix = ; if (IsAllPrintTitle) { MyHeadPix += Get_TableTileHeight(); } if (IsAllPrintHead) { MyHeadPix += Get_TableHeadHeight(); } if (IsAllPrintFoot) { MyFootPix = Get_TableFootHeight(); } } else // 执行直接数据分页 { Paging_Direct(, ref retPages); } } return retPages; } /// <summary> /// 直接分页 /// </summary> /// <param name="startR">开始行号</param> /// <param name="pages">页面数组</param> private void Paging_Direct(int startR, ref List<PagingItem> pages) { float p_Height = TableRect.Height; PagingItem p_Item = new PagingItem(); p_Item.PageNum = pages.Count + ; for (int t = startR; t < RowsList.Count; t++) { // 检查行内单元格是否不允许分页两种情况:条形码,图片 if (Paging_CheckCell(RowsList[t], p_Height)) { startR = t; pages.Add(p_Item); Paging_Direct(startR, ref pages); break; } else { p_Height -= RowsList[t].RowHeight; if (p_Height <= ) { startR = t; pages.Add(p_Item); Paging_Direct(startR, ref pages); break; } else { p_Item.IndexList.Add(t); if (t == RowsList.Count - ) { pages.Add(p_Item); } } } } } /// <summary> /// 相对分页 /// </summary> /// <param name="startR">开始序号</param> /// <param name="pages">页面数组</param> private void Paging_Relative(int startR, ref List<PagingItem> pages) { SplitReportArea(); // 拆分表行 float p_Height = TableRect.Height; // 页面总高 PagingItem p_Item = new PagingItem(); // 分页页面 p_Item.PageNum = pages.Count + ; // 分页页码 bool runNext = false; // 继续分页 #region 每页打印标题 // 每页打印标题 if (IsAllPrintTitle) { p_Height -= Get_TableTileHeight(); foreach (Row p_Row in TitleList) p_Item.IndexList.Add(p_Row.RowIndex); } else { if (p_Item.PageNum == ) // 第一页特殊处理 { p_Height -= Get_TableTileHeight(); foreach (Row p_Row in TitleList) p_Item.IndexList.Add(p_Row.RowIndex); } } #endregion #region 每页打印表头 // 每页打印表头 if (IsAllPrintHead) { if (p_Item.PageNum == ) // 第一页特殊处理 { // 计算表头前的行高 p_Height -= Get_TableHForHeight(); foreach (Row p_Row in HForeList) p_Item.IndexList.Add(p_Row.RowIndex); } // 计算表头行的高度 p_Height -= Get_TableHeadHeight(); foreach (Row p_Row in HeadList) p_Item.IndexList.Add(p_Row.RowIndex); } else { if (p_Item.PageNum == ) // 第一页特殊处理 { // 计算表头前的行高 p_Height -= Get_TableHForHeight(); foreach (Row p_Row in HForeList) p_Item.IndexList.Add(p_Row.RowIndex); // 计算表头行的高度 p_Height -= Get_TableHeadHeight(); foreach (Row p_Row in HeadList) p_Item.IndexList.Add(p_Row.RowIndex); } } #endregion #region 每页数据区域 // 每页数据划分 if (IsAllPrintFoot) { p_Height -= Get_TableFootHeight(); // 表格高度 先减去表尾的高度 } for (int t = startR; t < DataList.Count; t++) { // 检查行内单元格是否不允许分页两种情况:条形码,图片 if (Paging_CheckCell(DataList[t], p_Height)) // 此情况下,单元格不能分割,并且高度超过页面剩余高度,所以要启动新的一页 { startR = t; runNext = true; break; } else { p_Height -= DataList[t].RowHeight; if (p_Height <= ) { startR = t; runNext = true; break; } else { p_Item.IndexList.Add(DataList[t].RowIndex); } } } #endregion #region 每页打印表尾 // 每页打印表尾 if (IsAllPrintFoot) { foreach (Row p_Row in FootList) p_Item.IndexList.Add(p_Row.RowIndex); } #endregion #region 添加分页页面 pages.Add(p_Item); if (runNext) { Paging_Relative(startR, ref pages); } #endregion } /// <summary> /// 检查行内单元格如果是图片 /// 并且合并行数大于 /// </summary> /// <param name="cRow"></param> /// <param name="cHeight"></param> /// <returns></returns> private bool Paging_CheckCell(Row cRow, float cHeight) { foreach (Cell cCell in cRow.RowCells) { if (cCell.IsImage == true) { if (cCell.RectH > cHeight) return true; } } return false; } #endregion #region 辅助方法 /// <summary> /// 获取--报表全部高度 /// </summary> /// <returns></returns> private float Get_TableAllHeight() { float retHight = ; for (int k = ; k < RowsList.Count; k++) { Row t_Row = RowsList[k]; retHight += t_Row.RowHeight; } return retHight; } /// <summary> /// 获取是否设置了标题、表头、表尾 中的任意一个 /// </summary> /// <returns></returns> private bool Get_IsCusSet_THDF() { string tmType = ""; foreach (Row cusRow in this.RowsList) { tmType = cusRow.RowType.ToLower().Trim(); if (tmType == "t" || tmType == "h" || tmType == "f") return true; } return false; } /// <summary> /// 获取--报表标题高度 /// </summary> /// <returns></returns> private float Get_TableTileHeight() { float retHight = ; for (int k = ; k < TitleList.Count; k++) retHight += TitleList[k].RowHeight; return retHight; } /// <summary> /// 获取--报表表头前高度 /// </summary> /// <returns></returns> private float Get_TableHForHeight() { float retHight = ; for (int k = ; k < HForeList.Count; k++) retHight += HForeList[k].RowHeight; return retHight; } /// <summary> /// 获取--报表表头高度 /// </summary> /// <re【文章出处:台湾服务器 转载请保留连接】turns></returns> private float Get_TableHeadHeight() { float retHight = ; for (int k = ; k < HeadList.Count; k++) retHight += HeadList[k].RowHeight; return retHight; } /// <summary> /// 获取--报表表尾高度 /// </summary> /// <returns></returns> private float Get_TableFootHeight() { float retHight = ; for (int k = ; k < FootList.Count; k++) retHight += FootList[k].RowHeight; return retHight; } /// <summary> /// 拆分报表区域 /// </summary> public void SplitReportArea() { TitleList = new List<Row>(); HForeList = new List<Row>(); HeadList = new List<Row>(); DataList = new List<Row>(); FootList = new List<Row>(); for (int m = ; m < RowsList.Count; m++) { Row mmRow = RowsList[m]; switch (mmRow.RowType.ToLower()) { case "t": // 标题 TitleList.Add(mmRow); break; case "h": // 表头 HeadList.Add(mmRow); break; case "f": // 表尾 FootList.Add(mmRow); break; case "d": // 数据 default: DataList.Add(mmRow); break; } } // 设置表头前行集 if (TitleList.Count == && HeadList.Count > ) { List<Row> tmpList = new List<Row>(); for (int n = ; n < DataList.Count; n++) { if (DataList[n].RowIndex < HeadList[].RowIndex) { HForeList.Add(DataList[n]); tmpList.Add(DataList[n]); } } for (int n = ; n < tmpList.Count; n++) { DataList.Remove(tmpList[n]); } tmpList.Clear(); } // 重设表尾 不是每页打印表尾情况下,那么表位就去掉 if (!IsAllPrintFoot) { foreach (Row tRow in FootList) DataList.Add(tRow); FootList.Clear(); } } #endregion } }
4、PagingMakeUp 分页补充绘制类
using System; using System.Collections.Generic; using System.Text; namespace E_Print { /// <summary> /// 下页需要补充绘制 /// </summary> public class PagingMakeUp { /// <summary> /// 补充单元格 /// </summary> private Cell _makeupCell; /// <summary> /// 补充高度 /// </summary> private float _makeupHeight; /// <summary> /// 构造函数 /// </summary> public PagingMakeUp() { _makeupCell = new Cell(); _makeupHeight = ; } /// <summary> /// 获取--设置--补充单元格 /// </summary> public Cell MakeupCell { get { return _makeupCell; } set { _makeupCell = value; } } /// <summary> /// 获取--设置--补充高度 /// </summary> public float MakeupHeight { get { return _makeupHeight; } set { _makeupHeight = value; } } } }
5、IObjectSafety 抽象接口类
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace E_Print { /// <summary> /// 接口抽象基类 /// </summary> [ComImport, GuidAttribute("CBBDC-C-CF-F-FCD")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] public interface IObjectSafety { [PreserveSig] int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U)] ref int pdwEnabledOptions); [PreserveSig()] int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U)] int dwEnabledOptions); } }
6、预览效果
7、我们可以通过源码中的 EPrintTest.exe 打印Winform 实例 ,来执行示范,
通过WEB前端js 生成打印的TABLE的 RptData.xml格式 数据,在WINForm中直接使用
如果在网页中,通过JS 直接传给打印控件就OK