来源: 网页WEB打印控件制作 – SDP开发平台 – 博客园
在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 打印插件类
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Drawing;
5 using System.Data;
6 using System.Text;
7 using System.Windows.Forms;
8 using System.Runtime.InteropServices;
9 using System.Drawing.Printing;
10 using System.Xml;
11 using System.Security;
12 using System.Drawing.Drawing2D;
13 using System.Drawing.Text;
14 using System.Text.RegularExpressions;
15
16 namespace E_Print
17 {
18 /// <summary>
19 /// 打印控件
20 /// 实现IObjectSafety接口
21 /// 网页上所有所使用到的GUID 通过Guid工具生成的唯一编码
22 /// 74D1ED1D-B1A7-4039-A060-6F544FBE99EC 编码以后不允许修改
23 /// </summary>
24 [Guid("74D1ED1D-B1A7-4039-A060-6F544FBE99EC"), ProgId("EReportPrint"), ComVisible(true)]
25 public partial class PrintControl : UserControl, IObjectSafety
26 {
27 #region 私有变量
28
29 #region 通用参数
30
31 /// <summary>
32 /// 缩放比例
33 /// </summary>
34 private float Zoom = 1;
35
36 /// <summary>
37 /// 网页高度 像素 px
38 /// </summary>
39 private float HtmlHeight = 0;
40
41 /// <summary>
42 /// 网页宽度 像素 px
43 /// </summary>
44 private float HtmlWidth = 0;
45
46 /// <summary>
47 /// 报表区域矩形
48 /// </summary>
49 private RectangleF TableRect = new RectangleF();
50
51 /// <summary>
52 /// 报表绘制实例
53 /// </summary>
54 private ReportDraw RptDraw = new ReportDraw();
55
56 #endregion
57
58 #region 页边距
59
60 /// <summary>
61 /// 左边距
62 /// 毫米 mm(一位小数)
63 /// </summary>
64 private float _marginLeft = 9.9f;
65
66 /// <summary>
67 /// 右边距
68 /// </summary>
69 private float _marginRight = 9.9f;
70
71 /// <summary>
72 /// 上边距
73 /// </summary>
74 private float _marginTop = 9.9f;
75
76 /// <summary>
77 /// 下边距
78 /// </summary>
79 private float _marginBottom = 9.9f;
80
81 #endregion
82
83 #region 版型方向
84
85 /// <summary>
86 /// 版型方向 Landscape: true 横向;false 纵向
87 /// </summary>
88 private bool _landscape = false;
89
90 #endregion
91
92 #region 纸型大小
93
94 /// <summary>
95 /// 纸张类型
96 /// </summary>
97 private string _paperName = "A4";
98
99 /// <summary>
100 /// 纸张宽度
101 /// </summary>
102 private int _paperWidth = 210; // 毫米
103
104 /// <summary>
105 /// 纸张高度
106 /// </summary>
107 private int _paperHeight = 297; // 毫米
108
109 #endregion
110
111 #region 打印参数
112
113 /// <summary>
114 /// 自适应纸张大小方法
115 /// null: 无
116 /// row: 横向
117 /// col: 纵向
118 /// </summary>
119 private string _zoomType = "null";
120
121 /// <summary>
122 /// 是否每页打印标题
123 /// </summary>
124 private bool _isTblTitleAllPage = false;
125
126 /// <summary>
127 /// 是否每页打印表头
128 /// </summary>
129 private bool _isTblHeadAllPage = false;
130
131 /// <summary>
132 /// 是否每页打印表尾
133 /// </summary>
134 private bool _isTblFootAllPage = false;
135
136 /// <summary>
137 /// 最后一页自动补行
138 /// </summary>
139 private bool _isAutoFillRow = false;
140
141 /// <summary>
142 /// 字符溢出是否换行缩小处理方式
143 /// </summary>
144 private bool _isOverFlow = false;
145
146 /// <summary>
147 /// 打印数据
148 /// </summary>
149 private string _dataXml = "";
150
151 #endregion
152
153 #region 页眉参数
154
155 /// <summary>
156 /// 页眉--绘制页眉
157 /// </summary>
158 private bool _headDraw = false;
159
160 /// <summary>
161 /// 页眉--高度 毫米
162 /// 默认 10 刚好
163 /// </summary>
164 private float _headHeight = 10.0f;
165
166 /// <summary>
167 /// 页眉--左侧文字
168 /// </summary>
169 private string _headLeft = "";
170
171 /// <summary>
172 /// 页眉--中间文字
173 /// </summary>
174 private string _headCenter = "";
175
176 /// <summary>
177 /// 页眉--右侧文字
178 /// </summary>
179 private string _headRight = "";
180
181 /// <summary>
182 /// 页眉--字体名称
183 /// </summary>
184 private string _headFontName = "宋体";
185
186 /// <summary>
187 /// 页眉--字体大小
188 /// </summary>
189 private string _headFontSize = "9pt";
190
191 /// <summary>
192 /// 页眉--字体颜色
193 /// </summary>
194 private string _headFontColor = "Black";
195
196 /// <summary>
197 /// 页眉--字体--粗体
198 /// </summary>
199 private bool _headFontBold = false;
200
201 /// <summary>
202 /// 页眉--字体--斜体
203 /// </summary>
204 private bool _headFontItalic = false;
205
206 /// <summary>
207 /// 页眉--字体--删除线
208 /// </summary>
209 private bool _headFontStrikeout = false;
210
211 /// <summary>
212 /// 页眉--字体--下划线
213 /// </summary>
214 private bool _headFontUnderline = false;
215
216 /// <summary>
217 /// 页眉--绘制分隔线
218 /// </summary>
219 private bool _headLineDraw = false;
220
221 /// <summary>
222 /// 页眉--分隔线宽度
223 /// </summary>
224 private float _headLineWidth = 1.0f;
225
226 /// <summary>
227 /// 页眉--分隔线线型
228 /// </summary>
229 private string _headLineDash = "solid";
230
231 /// <summary>
232 /// 页眉--分隔线颜色
233 /// </summary>
234 private string _headLineColor = "Black";
235
236 #endregion
237
238 #region 页脚参数
239
240 /// <summary>
241 /// 页脚--绘制页脚
242 /// </summary>
243 private bool _footDraw = false;
244
245 /// <summary>
246 /// 页脚--高度 毫米
247 /// </summary>
248 private float _footHeight = 10.0f;
249
250 /// <summary>
251 /// 页脚--左侧文字
252 /// </summary>
253 private string _footLeft = "";
254
255 /// <summary>
256 /// 页脚--中间文字
257 /// </summary>
258 private string _footCenter = "";
259
260 /// <summary>
261 /// 页脚--右侧文字
262 /// </summary>
263 private string _footRight = "";
264
265 /// <summary>
266 /// 页脚--字体名称
267 /// </summary>
268 private string _footFontName = "宋体";
269
270 /// <summary>
271 /// 页脚--字体大小
272 /// </summary>
273 private string _footFontSize = "9pt";
274
275 /// <summary>
276 /// 页脚--字体颜色
277 /// </summary>
278 private string _footFontColor = "Black";
279
280 /// <summary>
281 /// 页脚--字体--粗体
282 /// </summary>
283 private bool _footFontBold = false;
284
285 /// <summary>
286 /// 页脚--字体--斜体
287 /// </summary>
288 private bool _footFontItalic = false;
289
290 /// <summary>
291 /// 页脚--字体--删除线
292 /// </summary>
293 private bool _footFontStrikeout = false;
294
295 /// <summary>
296 /// 页脚--字体--下划线
297 /// </summary>
298 private bool _footFontUnderline = false;
299
300 /// <summary>
301 /// 页脚--绘制分隔线
302 /// </summary>
303 private bool _footLineDraw = false;
304
305 /// <summary>
306 /// 页脚--分隔线宽度
307 /// </summary>
308 private float _footLineWidth = 1.0f;
309
310 /// <summary>
311 /// 页脚--分隔线线型
312 /// </summary>
313 private string _footLineDash = "solid";
314
315 /// <summary>
316 /// 页脚--分隔线颜色
317 /// </summary>
318 private string _footLineColor = "Black";
319
320 #endregion
321
322 #endregion
323
324 #region 构造方法
325
326 /// <summary>
327 /// 打印控件构造函数
328 /// </summary>
329 public PrintControl()
330 {
331 InitializeComponent();
332 Init_PageSetting();
333 }
334
335 #endregion
336
337 #region 接口实现
338
339 private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
340 private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
341 private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
342 private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
343 private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
344
345 private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
346 private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
347 private const int S_OK = 0;
348 private const int E_FAIL = unchecked((int)0x80004005);
349 private const int E_NOINTERFACE = unchecked((int)0x80004002);
350
351 private bool _fSafeForScripting = true;
352 private bool _fSafeForInitializing = true;
353
354 public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
355 {
356 int Rslt = E_FAIL;
357
358 string strGUID = riid.ToString("B");
359 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
360 switch (strGUID)
361 {
362 case _IID_IDispatch:
363 case _IID_IDispatchEx:
364 Rslt = S_OK;
365 pdwEnabledOptions = 0;
366 if (_fSafeForScripting == true)
367 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
368 break;
369 case _IID_IPersistStorage:
370 case _IID_IPersistStream:
371 case _IID_IPersistPropertyBag:
372 Rslt = S_OK;
373 pdwEnabledOptions = 0;
374 if (_fSafeForInitializing == true)
375 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
376 break;
377 default:
378 Rslt = E_NOINTERFACE;
379 break;
380 }
381
382 return Rslt;
383 }
384
385 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
386 {
387 int Rslt = E_FAIL;
388 string strGUID = riid.ToString("B");
389 switch (strGUID)
390 {
391 case _IID_IDispatch:
392 case _IID_IDispatchEx:
393 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
394 Rslt = S_OK;
395 break;
396 case _IID_IPersistStorage:
397 case _IID_IPersistStream:
398 case _IID_IPersistPropertyBag:
399 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
400 Rslt = S_OK;
401 break;
402 default:
403 Rslt = E_NOINTERFACE;
404 break;
405 }
406
407 return Rslt;
408 }
409
410 #endregion
411
412 #region 属性方法
413
414 #region 页边距
415
416 /// <summary>
417 /// 获取--设置--左边距
418 /// 计量单位 毫米(mm)
419 /// </summary>
420 public float MARGINLEFT
421 {
422 get { return _marginLeft; }
423 set { _marginLeft = value; }
424 }
425
426 /// <summary>
427 /// 获取--设置--右边距
428 /// 计量单位 毫米(mm)
429 /// </summary>
430 public float MARGINRIGHT
431 {
432 get { return _marginRight; }
433 set { _marginRight = value; }
434 }
435
436 /// <summary>
437 /// 获取--设置--上边距
438 /// 计量单位 毫米(mm)
439 /// </summary>
440 public float MARGINTOP
441 {
442 get { return _marginTop; }
443 set { _marginTop = value; }
444 }
445
446 /// <summary>
447 /// 获取--设置--下边距
448 /// 计量单位 毫米(mm)
449 /// </summary>
450 public float MARGINBOTTOM
451 {
452 get { return _marginBottom; }
453 set { _marginBottom = value; }
454 }
455
456 #endregion
457
458 #region 版型方向
459
460 /// <summary>
461 /// 获取--设置--版型方向
462 /// Landscape: true 横向; false 纵向
463 /// </summary>
464 public bool LANDSCAPE
465 {
466 get { return _landscape; }
467 set { _landscape = value; }
468 }
469
470 #endregion
471
472 #region 纸张属性
473
474 /// <summary>
475 /// 获取--设置--纸张类型
476 /// </summary>
477 public string PAPERNAME
478 {
479 get { return _paperName; }
480 set { _paperName = value; }
481 }
482
483 /// <summary>
484 /// 获取--设置--纸张高度
485 /// 计量单位 毫米(mm)
486 /// </summary>
487 public int PAPERHEIGHT
488 {
489 get { return _paperHeight; }
490 set { _paperHeight = value; }
491 }
492
493 /// <summary>
494 /// 获取--设置--纸张宽度
495 /// 计量单位 毫米(mm)
496 /// </summary>
497 public int PAPERWIDTH
498 {
499 get { return _paperWidth; }
500 set { _paperWidth = value; }
501 }
502
503 #endregion
504
505 #region 页眉参数
506
507 /// <summary>
508 /// 获取--设置--页眉是否绘制
509 /// </summary>
510 public bool HEADDRAW
511 {
512 get { return _headDraw; }
513 set { _headDraw = value; }
514 }
515
516 /// <summary>
517 /// 获取--设置--页眉高度
518 /// 单位:毫米整数类型
519 /// </summary>
520 public float HEADHEIGHT
521 {
522 get { return _headHeight; }
523 set { _headHeight = value; }
524 }
525
526 /// <summary>
527 /// 获取--设置--页眉左侧文字
528 /// </summary>
529 public string HEADLEFT
530 {
531 get { return _headLeft; }
532 set { _headLeft = value; }
533 }
534
535 /// <summary>
536 /// 获取--设置--页眉中间文字
537 /// </summary>
538 public string HEADCENTER
539 {
540 get { return _headCenter; }
541 set { _headCenter = value; }
542 }
543
544 /// <summary>
545 /// 获取--设置--页眉右侧文字
546 /// </summary>
547 public string HEADRIGHT
548 {
549 get { return _headRight; }
550 set { _headRight = value; }
551 }
552
553 /// <summary>
554 /// 获取--设置--页眉字体名称
555 /// </summary>
556 public string HEADFONTNAME
557 {
558 get { return _headFontName; }
559 set { _headFontName = value; }
560 }
561
562 /// <summary>
563 /// 获取--设置--页眉字体大小
564 /// </summary>
565 public string HEADFONTSIZE
566 {
567 get { return _headFontSize; }
568 set { _headFontSize = value; }
569 }
570
571 /// <summary>
572 /// 获取--设置--页眉字体颜色
573 /// </summary>
574 public string HEADFONTCOLOR
575 {
576 get { return _headFontColor; }
577 set { _headFontColor = value; }
578 }
579
580 /// <summary>
581 /// 获取--设置--页眉字体--粗体
582 /// </summary>
583 public bool HEADFONTBOLD
584 {
585 get { return _headFontBold; }
586 set { _headFontBold = value; }
587 }
588
589 /// <summary>
590 /// 获取--设置--页眉字体--斜体
591 /// </summary>
592 public bool HEADFONTITALIC
593 {
594 get { return _headFontItalic; }
595 set { _headFontItalic = value; }
596 }
597
598 /// <summary>
599 /// 获取--设置--页眉字体--删除线
600 /// </summary>
601 public bool HEADFONTSTRIKEOUT
602 {
603 get { return _headFontStrikeout; }
604 set { _headFontStrikeout = value; }
605 }
606
607 /// <summary>
608 /// 获取--设置--页眉字体--下划线
609 /// </summary>
610 public bool HEADFONTUNDERLINE
611 {
612 get { return _headFontUnderline; }
613 set { _headFontUnderline = value; }
614 }
615
616 /// <summary>
617 /// 获取--设置--是否绘制分割线
618 /// </summary>
619 public bool HEADLINEDRAW
620 {
621 get { return _headLineDraw; }
622 set { _headLineDraw = value; }
623 }
624
625 /// <summary>
626 /// 获取--设置--页眉分隔线宽度
627 /// </summary>
628 public float HEADLINEWIDTH
629 {
630 get { return _headLineWidth; }
631 set { _headLineWidth = value; }
632 }
633
634 /// <summary>
635 /// 获取--设置--页眉分隔线线型
636 /// </summary>
637 public string HEADLINEDASH
638 {
639 get { return _headLineDash; }
640 set { _headLineDash = value; }
641 }
642
643 /// <summary>
644 /// 获取--设置--页眉分隔线颜色
645 /// </summary>
646 public string HEADLINECOLOR
647 {
648 get { return _headLineColor; }
649 set { _headLineColor = value; }
650 }
651
652 #endregion
653
654 #region 页脚参数
655
656 /// <summary>
657 /// 获取--设置--页脚是否绘制
658 /// </summary>
659 public bool FOOTDRAW
660 {
661 get { return _footDraw; }
662 set { _footDraw = value; }
663 }
664
665 /// <summary>
666 /// 获取--设置--页脚高度
667 /// 单位:毫米整数类型
668 /// </summary>
669 public float FOOTHEIGHT
670 {
671 get { return _footHeight; }
672 set { _footHeight = value; }
673 }
674
675 /// <summary>
676 /// 获取--设置--页脚左侧文字
677 /// </summary>
678 public string FOOTLEFT
679 {
680 get { return _footLeft; }
681 set { _footLeft = value; }
682 }
683
684 /// <summary>
685 /// 获取--设置--页脚中间文字
686 /// </summary>
687 public string FOOTCENTER
688 {
689 get { return _footCenter; }
690 set { _footCenter = value; }
691 }
692
693 /// <summary>
694 /// 获取--设置--页脚右侧文字
695 /// </summary>
696 public string FOOTRIGHT
697 {
698 get { return _footRight; }
699 set { _footRight = value; }
700 }
701
702 /// <summary>
703 /// 获取--设置--页脚字体名称
704 /// </summary>
705 public string FOOTFONTNAME
706 {
707 get { return _footFontName; }
708 set { _footFontName = value; }
709 }
710
711 /// <summary>
712 /// 获取--设置--页脚字体大小
713 /// </summary>
714 public string FOOTFONTSIZE
715 {
716 get { return _footFontSize; }
717 set { _footFontSize = value; }
718 }
719
720 /// <summary>
721 /// 获取--设置--页脚字体颜色
722 /// </summary>
723 public string FOOTFONTCOLOR
724 {
725 get { return _footFontColor; }
726 set { _footFontColor = value; }
727 }
728
729 /// <summary>
730 /// 获取--设置--页脚字体--粗体
731 /// </summary>
732 public bool FOOTFONTBOLD
733 {
734 get { return _footFontBold; }
735 set { _footFontBold = value; }
736 }
737
738 /// <summary>
739 /// 获取--设置--页脚字体--斜体
740 /// </summary>
741 public bool FOOTFONTITALIC
742 {
743 get { return _footFontItalic; }
744 set { _footFontItalic = value; }
745 }
746
747 /// <summary>
748 /// 获取--设置--页脚字体--删除线
749 /// </summary>
750 public bool FOOTFONTSTRIKEOUT
751 {
752 get { return _footFontStrikeout; }
753 set { _footFontStrikeout = value; }
754 }
755
756 /// <summary>
757 /// 获取--设置--页脚字体--下划线
758 /// </summary>
759 public bool FOOTFONTUNDERLINE
760 {
761 get { return _footFontUnderline; }
762 set { _footFontUnderline = value; }
763 }
764
765 /// <summary>
766 /// 获取--设置--是否绘制分割线
767 /// </summary>
768 public bool FOOTLINEDRAW
769 {
770 get { return _footLineDraw; }
771 set { _footLineDraw = value; }
772 }
773
774 /// <summary>
775 /// 获取--设置--页脚分隔线宽度
776 /// </summary>
777 public float FOOTLINEWIDTH
778 {
779 get { return _footLineWidth; }
780 set { _footLineWidth = value; }
781 }
782
783 /// <summary>
784 /// 获取--设置--页脚分隔线线型
785 /// </summary>
786 public string FOOTLINEDASH
787 {
788 get { return _footLineDash; }
789 set { _footLineDash = value; }
790 }
791
792 /// <summary>
793 /// 获取--设置--页脚分隔线颜色
794 /// </summary>
795 public string FOOTLINECOLOR
796 {
797 get { return _footLineColor; }
798 set { _footLineColor = value; }
799 }
800
801 #endregion
802
803 #region 打印参数
804
805 /// <summary>
806 /// 获取--设置--打印数据
807 /// 前台传入的XML格式的打印数据
808 /// </summary>
809 public string DATAXML
810 {
811 get { return _dataXml; }
812 set { _dataXml = value; }
813 }
814
815 /// <summary>
816 /// 获取--设置--是否每页打印标题
817 /// </summary>
818 public bool ISTBLTITLEALLPAGE
819 {
820 get { return _isTblTitleAllPage; }
821 set { _isTblTitleAllPage = value; }
822 }
823
824 /// <summary>
825 /// 获取--设置--是否每页打印表头
826 /// </summary>
827 public bool ISTBLHEADALLPAGE
828 {
829 get { return _isTblHeadAllPage; }
830 set { _isTblHeadAllPage = value; }
831 }
832
833 /// <summary>
834 /// 获取--设置--是否每页打印表尾
835 /// </summary>
836 public bool ISTBLFOOTALLPAGE
837 {
838 get { return _isTblFootAllPage; }
839 set { _isTblFootAllPage = value; }
840 }
841
842 /// <summary>
843 /// 获取--设置--末页自动补行
844 /// </summary>
845 public bool ISAUTOFILLROW
846 {
847 get { return _isAutoFillRow; }
848 set { _isAutoFillRow = value; }
849 }
850
851 /// <summary>
852 /// 获取--设置--缩放方向
853 /// 参数:以下三种;默认null
854 /// null: 无
855 /// row: 横向
856 /// col: 纵向
857 /// </summary>
858 public string ZOOMTYPE
859 {
860 get { return _zoomType; }
861 set { _zoomType = value; }
862 }
863
864 /// <summary>
865 /// 获取--设置--字符溢出是否缩小换行处理方式
866 /// </summary>
867 public bool ISOVERFLOW
868 {
869 get { return _isOverFlow; }
870 set { _isOverFlow = value; }
871 }
872
873 #endregion
874
875 #region 加载参数
876
877 /// <summary>
878 /// 加载打印参数
879 /// </summary>
880 public void INITPRINTPARAM()
881 {
882 Init_PageSetting();
883 }
884
885 #endregion
886
887 #endregion
888
889 #region 加载事件
890
891 /// <summary>
892 /// 初始化--页面设置参数
893 /// </summary>
894 private void Init_PageSetting()
895 {
896 this.E_PrintDocument.DefaultPageSettings.Margins.Left = (int)Math.Round(MARGINLEFT * 10); // 左边距
897 this.E_PrintDocument.DefaultPageSettings.Margins.Right = (int)Math.Round(MARGINRIGHT * 10); // 右边距
898 this.E_PrintDocument.DefaultPageSettings.Margins.Top = (int)Math.Round(MARGINTOP * 10); // 上边距
899 this.E_PrintDocument.DefaultPageSettings.Margins.Bottom = (int)Math.Round(MARGINBOTTOM * 10); // 下边距
900
901 this.E_PrintDocument.PrinterSettings.Copies = 1; // 打印份数
902 this.E_PrintDocument.DefaultPageSettings.Landscape = this.LANDSCAPE; // 版型方向
903 PaperSize size = GetPaperSize(PAPERNAME); // 纸张类型
904 if (size != null)
905 this.E_PrintDocument.DefaultPageSettings.PaperSize = size;
906 else
907 this.E_PrintDocument.DefaultPageSettings.PaperSize = new PaperSize(this.PAPERNAME, (int)Math.Round(this.PAPERWIDTH / 25.4 * 100), (int)Math.Round(this.PAPERHEIGHT / 25.4 * 100));
908 }
909
910 /// <summary>
911 /// 获取--纸张类型
912 /// </summary>
913 /// <param name="paperName">纸张类型名称</param>
914 /// <returns></returns>
915 private PaperSize GetPaperSize(string paperName)
916 {
917 PaperSize paper = null;
918 foreach (PaperSize ps in this.E_PrintDocument.PrinterSettings.PaperSizes)
919 {
920 if (ps.PaperName.ToLower() == paperName.ToLower()) // 检查打印机是否有指定的纸张类型
921 {
922 paper = ps;
923 break;
924 }
925 }
926 return paper;
927 }
928
929 #endregion
930
931 #region 打印事件
932
933 /// <summary>
934 /// 直接打印
935 /// 此处加入了再次调用打印设置界面,因为用户可能需要选择那种打印机
936 /// </summary>
937 /// <returns></returns>
938 public string PRINT()
939 {
940 // 直接打印时,直接调用printDocument的Print()方法
941 // 因为用户可能在打印之前还要再更改打印设置所以需再次显示打印设置对话框
942 if (this.E_PrintDialog.ShowDialog() == DialogResult.OK)
943 {
944 try
945 {
946 this.Init_Printer();
947 this.E_PrintDocument.Print();
948 }
949 catch (Exception ex)
950 {
951 this.E_PrintDocument.PrintController.OnEndPrint(this.E_PrintDocument, new PrintEventArgs());
952 return ex.Message.ToString();
953 }
954 }
955 return "";
956 }
957
958 /// <summary>
959 /// 打印预览
960 /// 将打印的数据进行预览
961 /// </summary>
962 public string PREVIEW()
963 {
964 try
965 {
966 this.Init_Printer();
967 this.E_PrintPreviewDialog.ShowDialog();
968 }
969 catch (Exception ex)
970 {
971 return ex.Message.ToString();
972 }
973
974 return "";
975 }
976
977 /// <summary>
978 /// 页面设置
979 /// 设置打印的页面的纸张大小、纸型、页面边距
980 /// </summary>
981 public void PAGESTE()
982 {
983 // 页面设置对话框中使用的是公制长度计量单位 (厘米)
984 // 在.net中采用的是英制的计量单位 (英寸)
985 // 1英寸约等于2.54厘米,1厘米=10毫米
986 // 所以在下面中需要加入转换信息 将对话框中设置的页边距进行转换保存
987 // 设置传入的纸张信息
988 if (this.E_PageSetupDialog.ShowDialog() == DialogResult.OK) // 弹出页面设置对话框
989 {
990 if (System.Globalization.RegionInfo.CurrentRegion.IsMetric) // 转换页边距计量单位
991 this.E_PageSetupDialog.PageSettings.Margins = PrinterUnitConvert.Convert(this.E_PageSetupDialog.PageSettings.Margins, PrinterUnit.Display, PrinterUnit.TenthsOfAMillimeter);
992 this.E_PrintDocument.DefaultPageSettings = this.E_PageSetupDialog.PageSettings; // 更新页面设置参数值
993
994 // 更新参数
995 this.LANDSCAPE = this.E_PrintDocument.DefaultPageSettings.Landscape; // 版型方向
996 this.PAPERNAME = this.E_PrintDocument.DefaultPageSettings.PaperSize.PaperName; // 纸张类型
997 PaperSize tmPSize = this.E_PrintDocument.DefaultPageSettings.PaperSize; // 纸张尺寸
998 this.PAPERWIDTH = (int)Math.Round(tmPSize.Width * 25.4 / 100); // 纸张宽度
999 this.PAPERHEIGHT = (int)Math.Round(tmPSize.Height * 25.4 / 100); // 纸张高度
1000 this.MARGINLEFT = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Left / 10f, 1); // 左边距
1001 this.MARGINRIGHT = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Right / 10f, 1); // 右边距
1002 this.MARGINTOP = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Top / 10f, 1); // 上边距
1003 this.MARGINBOTTOM = (float)Math.Round(this.E_PrintDocument.DefaultPageSettings.Margins.Bottom / 10f, 1); // 下边距
1004 }
1005 }
1006
1007 /// <summary>
1008 /// 打印设置
1009 /// 设置打印机的信息(选择打印机、设置打印份数等信息)
1010 /// </summary>
1011 public void PRINTSET()
1012 {
1013 this.E_PrintDialog.ShowDialog();
1014 }
1015
1016 #endregion
1017
1018 #region 绘制对象
1019
1020 /// <summary>
1021 /// 打印及打印前初始化数据
1022 /// </summary>
1023 private void Init_Printer()
1024 {
1025 HtmlHeight = 0; // 网页报表高度
1026 HtmlWidth = 0; // 网页报表宽度
1027 CalcTableRect(); // 计算区域矩形
1028 RptDraw = new ReportDraw(); // 报表绘制实例
1029 RptDraw.IsAllPrintTitle = this._isTblTitleAllPage; // 每页打印标题
1030 RptDraw.IsAllPrintHead = this._isTblHeadAllPage; // 每页打印表头
1031 RptDraw.IsAllPrintFoot = this._isTblFootAllPage; // 每页打印表尾
1032 RptDraw.IsAutoFillRow = this._isAutoFillRow; // 末页自动补行
1033 RptDraw.IsOverFlow = this._isOverFlow; // 字符溢出缩小
1034 RptDraw.ReptRect = TableRect; // 赋值报表矩形
1035 if (!ParseXML()) return; // 解析报表数据
1036 CalcReportZoom(); // 计算缩小比例
1037 CalcZoomAllSize(); // 按比计算尺寸
1038 RptDraw.Zoom = this.Zoom; // 赋值缩小比例
1039 RptDraw.CalcPaging(); // 计算打印分页
1040 }
1041
1042 /// <summary>
1043 /// PrintDocument 对象打印绘制事件
1044 /// </summary>
1045 /// <param name="sender"></param>
1046 /// <param name="e"></param>
1047 private void E_PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
1048 {
1049 Graphics g = e.Graphics;
1050 g.Clear(Color.White);
1051 DrawHeader(g);
1052 DrawFooter(g);
1053 if (RptDraw.DrawReport(g))
1054 e.HasMorePages = true;
1055 else
1056 e.HasMorePages = false;
1057
1058 }
1059
1060 /// <summary>
1061 /// 绘制页眉
1062 /// </summary>
1063 /// <param name="g">绘图对象</param>
1064 private void DrawHeader(Graphics g)
1065 {
1066 // 是否绘制
1067 if (_headDraw)
1068 {
1069 // 页眉实例
1070 PageHeader pgHeader = new PageHeader();
1071
1072 // 页眉矩形
1073 RectangleF pgHeaderRect = new RectangleF(TableRect.X, // X 坐标
1074 TableRect.Y - mmToPixel(_headHeight), // Y 坐标
1075 TableRect.Width, // W 宽度
1076 mmToPixel(_headHeight) // H 高度
1077 );
1078
1079 // 页眉赋值
1080 pgHeader.HeadRect = pgHeaderRect;
1081 pgHeader.StrLeft = ReplacePageNum(_headLeft); // 左侧文本
1082 pgHeader.StrCenter = ReplacePageNum(_headCenter); // 中间文本
1083 pgHeader.StrRight = ReplacePageNum(_headRight); // 右侧文本
1084 FontStyle fontStyle = FontStyle.Regular; // 字体样式
1085 if (_headFontBold) fontStyle |= FontStyle.Bold;
1086 if (_headFontItalic) fontStyle |= FontStyle.Italic;
1087 if (_headFontStrikeout) fontStyle |= FontStyle.Strikeout;
1088 if (_headFontUnderline) fontStyle |= FontStyle.Underline;
1089
1090 pgHeader.StrFont = new Font(_headFontName, (float)Convert.ToDouble(_headFontSize.ToLower().Replace("px", "").Replace("pt", "")), fontStyle, GraphicsUnit.Point);
1091 pgHeader.StrColor = (Color)PrintTool.StrToColor(_headFontColor);
1092 if (_headLineDraw) // 绘制分割线
1093 {
1094 pgHeader.LineDraw = _headLineDraw;
1095 pgHeader.LineWidth = _headLineWidth;
1096 pgHeader.LineColor = (Color)PrintTool.StrToColor(_headLineColor);
1097 pgHeader.LineDash = PrintTool.GetDashStyle(_headLineDash);
1098 }
1099
1100 // 页眉绘制
1101 pgHeader.Draw(g);
1102 }
1103 }
1104
1105 /// <summary>
1106 /// 绘制页脚
1107 /// </summary>
1108 /// <param name="g">绘图对象</param>
1109 private void DrawFooter(Graphics g)
1110 {
1111 // 是否绘制
1112 if (_footDraw)
1113 {
1114 // 页脚实例
1115 PageFooter pgFooter = new PageFooter();
1116
1117 // 页脚矩形
1118 RectangleF pgFooterRect = new RectangleF(TableRect.X, // X 坐标
1119 TableRect.Y + TableRect.Height, // Y 坐标
1120 TableRect.Width, // W 宽度
1121 mmToPixel(_footHeight) // H 高度
1122 );
1123 // 页脚赋值
1124 pgFooter.FootRect = pgFooterRect;
1125 pgFooter.StrLeft = ReplacePageNum(_footLeft); // 左侧文本
1126 pgFooter.StrCenter = ReplacePageNum(_footCenter); // 中间文本
1127 pgFooter.StrRight = ReplacePageNum(_footRight); // 右侧文本
1128 FontStyle fontStyle = FontStyle.Regular; // 字体样式
1129 if (_footFontBold) fontStyle |= FontStyle.Bold;
1130 if (_footFontItalic) fontStyle |= FontStyle.Italic;
1131 if (_footFontStrikeout) fontStyle |= FontStyle.Strikeout;
1132 if (_footFontUnderline) fontStyle |= FontStyle.Underline;
1133
1134 pgFooter.StrFont = new Font(_footFontName, (float)Convert.ToDouble(_footFontSize.ToLower().Replace("px", "").Replace("pt", "")), fontStyle, GraphicsUnit.Point);
1135 pgFooter.StrColor = (Color)PrintTool.StrToColor(_footFontColor);
1136 if (_footLineDraw) // 绘制分割线
1137 {
1138 pgFooter.LineDraw = _footLineDraw;
1139 pgFooter.LineWidth = _footLineWidth;
1140 pgFooter.LineColor = (Color)PrintTool.StrToColor(_footLineColor);
1141 pgFooter.LineDash = PrintTool.GetDashStyle(_footLineDash);
1142 }
1143
1144 // 页脚绘制
1145 pgFooter.Draw(g);
1146 }
1147 }
1148
1149 #endregion
1150
1151 #region 辅助方法
1152
1153 /// <summary>
1154 /// 毫米 TO 像素
1155 /// </summary>
1156 /// <param name="mmValue">毫米值</param>
1157 /// <returns></returns>
1158 public static float mmToPixel(float mmValue) //mmValue是毫米,1厘米=10毫米
1159 {
1160 return (mmValue / 25.4f * 100f);
1161 }
1162
1163 /// <summary>
1164 /// 替换 当前页码、总共页数两个变量
1165 /// </summary>
1166 /// <param name="str"></param>
1167 /// <returns></returns>
1168 private string ReplacePageNum(string str)
1169 {
1170 string retStr = "";
1171 if (str == null || str.Trim() == "")
1172 return retStr;
1173 retStr = str;
1174 int t = 0;
1175 while (t >= 0)
1176 {
1177 t = retStr.IndexOf("[curpage]", StringComparison.OrdinalIgnoreCase);
1178 if (t >= 0)
1179 {
1180 retStr = retStr.Substring(0, t) + RptDraw.CurPageNum.ToString() + retStr.Substring(t + "[curpage]".Length);
1181 }
1182 }
1183
1184 t = 0;
1185 while (t >= 0)
1186 {
1187 t = retStr.IndexOf("[allpage]", StringComparison.OrdinalIgnoreCase);
1188 if (t >= 0)
1189 {
1190 retStr = retStr.Substring(0, t) + RptDraw.AllPageNum.ToString() + retStr.Substring(t + "[allpage]".Length);
1191 }
1192 }
1193 return retStr;
1194 }
1195
1196 /// <summary>
1197 /// 解析XML文件
1198 /// </summary>
1199 /// <returns>返回成功与否</returns>
1200 private bool ParseXML()
1201 {
1202 if (this.DATAXML == null || this.DATAXML.Trim() == "") return false;
1203 XmlDataDocument xmlDoc = new XmlDataDocument();
1204 try
1205 {
1206 xmlDoc.LoadXml(this.DATAXML);
1207 XmlNode rootNode = xmlDoc.DocumentElement;
1208 if (rootNode.ChildNodes.Count == 0) return false;
1209 if (rootNode.ChildNodes[0].Name.ToLower() != "table") return false;
1210
1211 XmlNode tableNode = rootNode.ChildNodes[0]; // 表格节点
1212 HtmlHeight = float.Parse(tableNode.Attributes["height"].Value);
1213 HtmlWidth = float.Parse(tableNode.Attributes["width"].Value);
1214
1215 int tmRowIndex = 0;
1216 foreach (XmlNode trNode in tableNode.ChildNodes)
1217 {
1218 if (trNode.Name.ToLower() != "tr") continue;
1219
1220 // 解析表格行
1221 Row tmRow = new Row();
1222 tmRow.RowIndex = tmRowIndex;
1223 tmRow.RowHeight = float.Parse(trNode.Attributes["height"].Value);
1224 tmRow.RowType = trNode.Attributes["rowtype"].Value.ToLower();
1225
1226 // 解析单元格
1227 foreach (XmlNode tdNode in trNode.ChildNodes)
1228 {
1229 Cell tmCell = new Cell();
1230
1231 #region 合并\坐标\矩形
1232
1233 tmCell.RowSpan = Convert.ToInt32(tdNode.Attributes["rowspan"].Value);
1234 tmCell.ColSpan = Convert.ToInt32(tdNode.Attributes["colspan"].Value);
1235 tmCell.RowIndex = Convert.ToInt32(tdNode.Attributes["r"].Value);
1236 tmCell.ColIndex = Convert.ToInt32(tdNode.Attributes["c"].Value);
1237 tmCell.RectX = float.Parse(tdNode.Attributes["x"].Value);
1238 tmCell.RectY = float.Parse(tdNode.Attributes["y"].Value);
1239 tmCell.RectW = float.Parse(tdNode.Attributes["w"].Value);
1240 tmCell.RectH = float.Parse(tdNode.Attributes["h"].Value);
1241
1242 #endregion
1243
1244 #region 设置单元格字体
1245
1246 FontStyle tmStyle = new FontStyle();
1247 tmStyle = FontStyle.Regular;
1248 if (tdNode.Attributes["italic"].Value.ToString() == "1") tmStyle |= FontStyle.Italic;
1249 if (tdNode.Attributes["bold"].Value.ToString() == "1") tmStyle |= FontStyle.Bold;
1250 if (tdNode.Attributes["strikeout"].Value.ToString() == "1") tmStyle |= FontStyle.Strikeout;
1251 if (tdNode.Attributes["underline"].Value.ToString() == "1") tmStyle |= FontStyle.Underline;
1252 tmCell.CellFont = new Font(tdNode.Attributes["fontname"].Value, float.Parse(tdNode.Attributes["fontsize"].Value.Replace("pt", "").Replace("px", "")), tmStyle, GraphicsUnit.Point);
1253 tmCell.FontColor = (Color)PrintTool.StrToColor(tdNode.Attributes["fontcolor"].Value);
1254 tmCell.BackColor = (Color)PrintTool.StrToColor(tdNode.Attributes["backcolor"].Value);
1255
1256 StringFormat tmFormat = new StringFormat();
1257 switch (tdNode.Attributes["align"].Value.ToLower()) // 水平对齐方式
1258 {
1259 case "center":
1260 tmFormat.Alignment = StringAlignment.Center;
1261 break;
1262 case "right":
1263 tmFormat.Alignment = StringAlignment.Far;
1264 break;
1265 default:
1266 tmFormat.Alignment = StringAlignment.Near;
1267 break;
1268 }
1269 switch (tdNode.Attributes["valign"].Value.ToLower()) // 垂直对齐方式
1270 {
1271 case "middle":
1272 tmFormat.LineAlignment = StringAlignment.Center;
1273 break;
1274 case "bottom":
1275 tmFormat.LineAlignment = StringAlignment.Far;
1276 break;
1277 default:
1278 tmFormat.LineAlignment = StringAlignment.Near;
1279 break;
1280 }
1281 tmCell.strFormat = tmFormat;
1282
1283 #endregion
1284
1285 #region 内嵌图片-属性
1286
1287 tmCell.IsImage = tdNode.Attributes["isimage"].Value.ToString() == "1" ? true : false;
1288 if (tmCell.IsImage)
1289 tmCell.ImageUrl = tdNode.Attributes["imageurl"].Value;
1290 #endregion
1291
1292 #region 单元格边框属性
1293
1294 // 左边框线
1295 string tmVal = tdNode.Attributes["leftwidth"].Value;
1296 if (tmVal.IndexOf("px") >= 0)
1297 {
1298 tmCell.LeftBorder = new BorderLine(
1299 float.Parse(tmVal.Replace("px", "")),
1300 (Color)PrintTool.StrToColor(tdNode.Attributes["leftcolor"].Value),
1301 PrintTool.GetDashStyle(tdNode.Attributes["leftdash"].Value)
1302 );
1303 }
1304
1305 // 上边框线
1306 tmVal = tdNode.Attributes["topwidth"].Value;
1307 if (tmVal.IndexOf("px") >= 0)
1308 {
1309 tmCell.TopBorder = new BorderLine(
1310 float.Parse(tmVal.Replace("px", "")),
1311 (Color)PrintTool.StrToColor(tdNode.Attributes["topcolor"].Value),
1312 PrintTool.GetDashStyle(tdNode.Attributes["topdash"].Value)
1313 );
1314
1315 }
1316
1317 // 右边框线
1318 tmVal = tdNode.Attributes["rightwidth"].Value;
1319 if (tmVal.IndexOf("px") >= 0)
1320 {
1321 tmCell.RightBorder = new BorderLine(
1322 float.Parse(tmVal.Replace("px", "")),
1323 (Color)PrintTool.StrToColor(tdNode.Attributes["rightcolor"].Value),
1324 PrintTool.GetDashStyle(tdNode.Attributes["rightdash"].Value)
1325 );
1326 }
1327
1328 // 下边框线
1329 tmVal = tdNode.Attributes["bottomwidth"].Value;
1330 if (tmVal.IndexOf("px") >= 0)
1331 {
1332 tmCell.BottomBorder = new BorderLine(
1333 float.Parse(tmVal.Replace("px", "")),
1334 (Color)PrintTool.StrToColor(tdNode.Attributes["bottomcolor"].Value),
1335 PrintTool.GetDashStyle(tdNode.Attributes["bottomdash"].Value)
1336 );
1337 }
1338
1339 #endregion
1340
1341 #region 单据格数据数值
1342
1343 tmCell.Value = tdNode.InnerText;
1344
1345 #endregion
1346
1347 // 加入对应的行内
1348 tmRow.RowCells.Add(tmCell);
1349 }
1350
1351 RptDraw.RowsList.Add(tmRow);
1352
1353 tmRowIndex++;
1354 }
1355 }
1356 catch
1357 {
1358 return false;
1359 }
1360 finally
1361 {
1362 xmlDoc = null;
1363 }
1364
1365 return true;
1366 }
1367
1368 /// <summary>
1369 /// 计算报表区域矩形
1370 /// 真实的绘制报表的区域
1371 /// </summary>
1372 private void CalcTableRect()
1373 {
1374 // 重新初始化实例
1375 TableRect = new RectangleF();
1376
1377 // 左顶点 X坐标
1378 TableRect.X = mmToPixel(_marginLeft);
1379
1380 // 左顶点 Y坐标
1381 TableRect.Y = mmToPixel(_marginTop);
1382 if (_headDraw) // 需要绘制页眉
1383 TableRect.Y += mmToPixel(_headHeight);
1384
1385 // 报表矩形宽度高度
1386 if (this.LANDSCAPE) // 版型方向 横向
1387 {
1388 // 颠倒 宽高
1389 TableRect.Width = mmToPixel((float)_paperHeight - _marginLeft - _marginRight);
1390 TableRect.Height = mmToPixel((float)_paperWidth - _marginTop - _marginBottom);
1391 }
1392 else // 版型方向 纵向
1393 {
1394 TableRect.Width = mmToPixel((float)_paperWidth - _marginLeft - _marginRight);
1395 TableRect.Height = mmToPixel((float)_paperHeight - _marginTop - _marginBottom);
1396 }
1397
1398 // 报表矩形高度缩减
1399 if (_headDraw) // 需要绘制页眉
1400 TableRect.Height -= mmToPixel(_headHeight);
1401 if (_footDraw) // 需要绘制页脚
1402 TableRect.Height -= mmToPixel(_footHeight);
1403 }
1404
1405 /// <summary>
1406 /// 计算缩放比例
1407 /// </summary>
1408 private void CalcReportZoom()
1409 {
1410 if (this.ZOOMTYPE.ToLower() == "row")
1411 {
1412 if (Convert.ToInt32(TableRect.Width) >= HtmlWidth)
1413 this.Zoom = 1;
1414 else
1415 this.Zoom = TableRect.Width / HtmlWidth;
1416 }
1417 else if (this.ZOOMTYPE.ToLower() == "col")
1418 {
1419 if (Convert.ToInt32(TableRect.Height) >= HtmlHeight)
1420 this.Zoom = 1;
1421 else
1422 this.Zoom = TableRect.Height / HtmlHeight;
1423 }
1424 else
1425 {
1426 this.Zoom = 1;
1427 }
1428 }
1429
1430 /// <summary>
1431 /// 转换所有的尺寸
1432 /// 根据缩放比例
1433 /// </summary>
1434 private void CalcZoomAllSize()
1435 {
1436 if (this.Zoom != 1)
1437 {
1438 // 转换HTML 高度宽度
1439 HtmlWidth = HtmlWidth * Zoom;
1440 HtmlHeight = HtmlHeight * Zoom;
1441
1442 // 转换所有行号
1443 foreach (Row zRow in this.RptDraw.RowsList)
1444 {
1445 // 行高缩小
1446 zRow.RowHeight = zRow.RowHeight * Zoom;
1447
1448 // 转换所有单元格
1449 foreach (Cell zCell in zRow.RowCells)
1450 {
1451 zCell.RectX = zCell.RectX * Zoom;
1452 zCell.RectY = zCell.RectY * Zoom;
1453 zCell.RectW = zCell.RectW * Zoom;
1454 zCell.RectH = zCell.RectH * Zoom;
1455
1456 zCell.TopBorder.LineWidth = zCell.TopBorder.LineWidth * Zoom;
1457 zCell.BottomBorder.LineWidth = zCell.BottomBorder.LineWidth * Zoom;
1458 zCell.LeftBorder.LineWidth = zCell.LeftBorder.LineWidth * Zoom;
1459 zCell.RightBorder.LineWidth = zCell.RightBorder.LineWidth * Zoom;
1460
1461 // 字体相应缩小
1462 zCell.CellFont = new Font(zCell.CellFont.Name, zCell.CellFont.Size * Zoom, zCell.CellFont.Style, GraphicsUnit.Point);
1463
1464 }
1465 }
1466 }
1467 }
1468
1469 #endregion
1470
1471 }
1472 }
2、ReportDraw 打印绘制类
1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Drawing.Drawing2D;
5 using System.IO;
6
7 namespace E_Print
8 {
9 /// <summary>
10 /// 报表绘制
11 /// </summary>
12 public class ReportDraw
13 {
14 #region 私有成员
15
16 /// <summary>
17 /// 当前页码
18 /// </summary>
19 private int _curPageNum;
20
21 /// <summary>
22 /// 总共页数
23 /// </summary>
24 private int _allPageNum;
25
26 /// <summary>
27 /// 表格矩形
28 /// </summary>
29 private RectangleF _reptRect;
30
31 /// <summary>
32 /// 报表全部行集
33 /// </summary>
34 private List<Row> _rowsList;
35
36 /// <summary>
37 /// 分页页面数组
38 /// </summary>
39 private List<PagingItem> _pageList;
40
41 /// <summary>
42 /// 是否每页打印标题
43 /// </summary>
44 private bool _isAllPrintTitle;
45
46 /// <summary>
47 /// 是否每页打印表头
48 /// </summary>
49 private bool _isAllPrintHead;
50
51 /// <summary>
52 /// 是否每页打印表尾
53 /// </summary>
54 private bool _isAllPrintFoot;
55
56 /// <summary>
57 /// 是否末页自动补行
58 /// </summary>
59 private bool _isAutoFillRow;
60
61 /// <summary>
62 /// 缩小比例
63 /// </summary>
64 private float _zoom;
65
66 /// <summary>
67 /// 字符溢出处理方式
68 /// </summary>
69 private bool _isOverFlow;
70
71 /// <summary>
72 /// 每页打印的标题+表头的高度
73 /// </summary>
74 private float _headPix;
75
76 /// <summary>
77 /// 每页打印的表尾高度
78 /// </summary>
79 private float _footPix;
80
81 #endregion
82
83 #region 构造方法
84
85 /// <summary>
86 /// 构造函数
87 /// </summary>
88 public ReportDraw()
89 {
90 _curPageNum = 1;
91 _allPageNum = 1;
92 _reptRect = new RectangleF();
93 _rowsList = new List<Row>();
94 _pageList = new List<PagingItem>();
95
96 _isAllPrintTitle = false;
97 _isAllPrintHead = false;
98 _isAllPrintFoot = false;
99 _isAutoFillRow = false;
100
101 _zoom = 1;
102 _isOverFlow = false;
103 _headPix = 0;
104 _footPix = 0;
105 }
106
107 /// <summary>
108 /// 构造函数
109 /// </summary>
110 /// <param name="printTitle">每页打印标题</param>
111 /// <param name="printHead">每页打印表头</param>
112 /// <param name="printFoot">每页打印表位</param>
113 /// <param name="fillRows">自动补全空行</param>
114 /// <param name="tableRect">报表尺寸矩形</param>
115 /// <param name="overFlow">字符溢出处理</param>
116 public ReportDraw(bool printTitle, bool printHead, bool printFoot, bool fillRows, RectangleF tableRect, bool overFlow)
117 {
118
119 _reptRect = tableRect;
120 _isAllPrintTitle = printTitle;
121 _isAllPrintHead = printHead;
122 _isAllPrintFoot = printFoot;
123 _isAutoFillRow = fillRows;
124 _isOverFlow = overFlow;
125
126 _curPageNum = 1;
127 _allPageNum = 1;
128 _zoom = 1;
129 _rowsList = new List<Row>();
130 _pageList = new List<PagingItem>();
131
132 _headPix = 0;
133 _footPix = 0;
134 }
135
136 #endregion
137
138 #region 属性方法
139
140 /// <summary>
141 /// 获取--设置--当前页码
142 /// </summary>
143 public int CurPageNum
144 {
145 get { return _curPageNum; }
146 set { _curPageNum = value; }
147 }
148
149 /// <summary>
150 /// 获取--设置--总共页数
151 /// </summary>
152 public int AllPageNum
153 {
154 get { return _allPageNum; }
155 set { _allPageNum = value; }
156 }
157
158 /// <summary>
159 /// 获取--设置--表格矩形
160 /// </summary>
161 public RectangleF ReptRect
162 {
163 get { return _reptRect; }
164 set { _reptRect = value; }
165 }
166
167 /// <summary>
168 /// 获取--设置--报表全部行集
169 /// </summary>
170 public List<Row> RowsList
171 {
172 get { return _rowsList; }
173 set { _rowsList = value; }
174 }
175
176 /// <summary>
177 /// 获取--设置--分页页面数组
178 /// </summary>
179 public List<PagingItem> PageList
180 {
181 get { return _pageList; }
182 set { _pageList = value; }
183 }
184
185 /// <summary>
186 /// 获取--设置--是否每页打印标题
187 /// </summary>
188 public bool IsAllPrintTitle
189 {
190 get { return _isAllPrintTitle; }
191 set { _isAllPrintTitle = value; }
192 }
193
194 /// <summary>
195 /// 获取--设置--是否每页打印表头
196 /// </summary>
197 public bool IsAllPrintHead
198 {
199 get { return _isAllPrintHead; }
200 set { _isAllPrintHead = value; }
201 }
202
203 /// <summary>
204 /// 获取--设置--是否每页打印表尾
205 /// </summary>
206 public bool IsAllPrintFoot
207 {
208 get { return _isAllPrintFoot; }
209 set { _isAllPrintFoot = value; }
210 }
211
212 /// <summary>
213 /// 获取--设置--末页是否自动补行
214 /// </summary>
215 public bool IsAutoFillRow
216 {
217 get { return _isAutoFillRow; }
218 set { _isAutoFillRow = value; }
219 }
220
221 /// <summary>
222 /// 获取--设置--缩小比例
223 /// </summary>
224 public float Zoom
225 {
226 get { return _zoom; }
227 set { _zoom = value; }
228 }
229
230 /// <summary>
231 /// 获取--设置--字符溢出处理方式
232 /// </summary>
233 public bool IsOverFlow
234 {
235 get { return _isOverFlow; }
236 set { _isOverFlow = value; }
237 }
238
239 /// <summary>
240 /// 获取--设置--每页打印的标题+表头高度
241 /// </summary>
242 public float HeadPix
243 {
244 get { return _headPix; }
245 set { _headPix = value; }
246 }
247
248 /// <summary>
249 /// 获取--设置--每页打印的表尾高度
250 /// </summary>
251 public float FootPix
252 {
253 get { return _footPix; }
254 set { _footPix = value; }
255 }
256
257 #endregion
258
259 #region 计算分页
260
261 /// <summary>
262 /// 计算分页
263 /// </summary>
264 public void CalcPaging()
265 {
266 // 分页实例
267 PagingCalc insCalc = new PagingCalc();
268 insCalc.TableRect = this.ReptRect;
269 insCalc.RowsList = this.RowsList;
270 insCalc.IsAllPrintTitle = this.IsAllPrintTitle;
271 insCalc.IsAllPrintHead = this.IsAllPrintHead;
272 insCalc.IsAllPrintFoot = this.IsAllPrintFoot;
273
274 // 分页计算
275 _pageList = insCalc.CalcPages();
276 this._allPageNum = _pageList.Count;
277 this._curPageNum = 1;
278
279 this._headPix = insCalc.MyHeadPix;
280 this._footPix = insCalc.MyFootPix;
281 }
282
283 #endregion
284
285 #region 绘制方法
286
287 /// <summary>
288 /// 绘制报表
289 /// </summary>
290 /// <param name="g"></param>
291 /// <returns>返回是否结束</returns>
292 public bool DrawReport(Graphics g)
293 {
294 bool isMorePage = false;
295 float offsetX = _reptRect.X; // X 偏移量
296 float offsetY = _reptRect.Y; // Y 偏移量
297
298 bool isCanFillRow = false; // 是否需要补行
299 bool isFillFlag = false; // 是否已经补过
300 int isFillRowNum = 0; // 需要补充几行
301
302 PagingItem nowPage = GetPageItem(CurPageNum); // 当前页
303 if (nowPage != null)
304 {
305 #region 判定高度不足是否自动补行
306
307 // 判定补行条件 报表设置了末页不足自动补行、同时 为最后一页
308 if (_isAutoFillRow == true && CurPageNum == AllPageNum)
309 {
310 // 判定页面高度 与 数据高度
311 float N_PageHeith = ReptRect.Height; // 当前页面高度
312 float N_DataHeith = GetThisPageDataRowsHeight(); // 当前数据高度
313
314 // 补行行高21
315 while ((N_DataHeith + (isFillRowNum + 1) * 21 * Zoom) < N_PageHeith)
316 {
317 isFillRowNum++;
318 }
319
320 if (isFillRowNum > 0)
321 isCanFillRow = true;
322 }
323
324 #endregion
325
326 #region 首先绘制上一页补充单元格
327
328 if (CurPageNum > 1)
329 {
330 PagingItem prePage = GetPageItem(CurPageNum - 1); // 上一页
331 if (prePage != null)
332 {
333 foreach (PagingMakeUp tmMk in prePage.MakeupList)
334 {
335 // 绘制补充单元格(上页中未绘制完成的单元格)
336 DrawTD(g, tmMk.MakeupCell, offsetX, offsetY, true, tmMk.MakeupHeight, false);
337 }
338 }
339 }
340
341 #endregion
342
343 #region 其次绘制当前页面的单元格
344
345 // 其次绘制当前页的单元格
346 for (int ii = 0; ii < nowPage.IndexList.Count; ii++)
347 {
348 // 先绘制 TD CELL 单元格
349 Row rowTR = GetRow(nowPage.IndexList[ii]);
350
351 #region 执行补行
352
353 if (isCanFillRow == true && rowTR.RowType.ToLower().Trim() == "f") // 需要补行 行标志为F 表尾前进行补充空行
354 {
355 Row fillRow = new Row();
356 if (ii == 0)
357 fillRow = rowTR;
358 else
359 fillRow = GetRow(nowPage.IndexList[ii - 1]);
360 if (fillRow != null) // 绘制自动补充的空行单元格
361 {
362 // 开始补充空行
363 for (int fi = 1; fi <= isFillRowNum; fi++)
364 {
365 bool bcFlag = true;
366 // 绘制单元格
367 foreach (Cell fillTdCell in fillRow.RowCells)
368 {
369 if (bcFlag)
370 {
371 // 绘制边框线(合并单元格的情况才用到)
372 if (fillTdCell.RectX > 0)
373 {
374 DrawLine(g, offsetX, offsetY, offsetX, offsetY + 21.0F * Zoom); // 最左边竖线
375 DrawLine(g, offsetX, offsetY + 21.0F * Zoom, offsetX + fillTdCell.RectX, offsetY + 21.0F * Zoom);
376 }
377 bcFlag = false;
378 }
379 DrawTD(g, fillTdCell, offsetX, offsetY, false, 0, true);
380 }
381
382 // 再将偏移量+行号 补充的行高全部为21px
383 offsetY += 21 * Zoom;
384 }
385 }
386
387 isFillFlag = true;
388 }
389
390 #endregion
391
392 #region 正常绘制
393
394 foreach (Cell td in rowTR.RowCells)
395 {
396 DrawTD(g, td, offsetX, offsetY, false, 0, false);
397 }
398
399 // 再将偏移量+行号
400 offsetY += rowTR.RowHeight;
401
402 #endregion
403 }
404
405 // 判定是否补过;没有补充过,则在最后进行补充空行
406 if ((isCanFillRow == true) && (isFillFlag == false) && (nowPage.IndexList.Count > 0))
407 {
408 Row fillRow = GetRow(nowPage.IndexList[nowPage.IndexList.Count - 1]);
409 if (fillRow != null) // 绘制自动补充的空行单元格
410 {
411
412 // 开始补充空行
413 for (int fi = 1; fi <= isFillRowNum; fi++)
414 {
415 bool newFlag = true;
416 foreach (Cell fillTdCell in fillRow.RowCells)
417 {
418 if (newFlag)
419 {
420 // 绘制边框线(合并单元格的情况才用到)
421 if (fillTdCell.RectX > 0)
422 {
423 DrawLine(g, offsetX, offsetY, offsetX, offsetY + 21.0F * Zoom); // 最左边竖线
424 DrawLine(g, offsetX, offsetY + 21.0F * Zoom, offsetX + fillTdCell.RectX, offsetY + 21.0F * Zoom);
425 }
426 newFlag = false;
427 }
428 DrawTD(g, fillTdCell, offsetX, offsetY, false, 0, true);
429 }
430 offsetY += 21 * Zoom; // 再将偏移量+行号 补充的行高全部为21px
431 }
432 }
433 }
434
435 #endregion
436
437 if (CurPageNum < AllPageNum)
438 {
439 isMorePage = true; // 还有下页
440 CurPageNum++; // 页码增加
441 }
442 }
443 return isMorePage;
444 }
445
446 /// <summary>
447 /// 绘制单元格
448 /// </summary>
449 /// <param name="g">绘图对象</param>
450 /// <param name="tdCell">单元格</param>
451 /// <param name="setX">X偏移量</param>
452 /// <param name="setY">Y坐标值</param>
453 /// <param name="isMakeup">是否补充单元格</param>
454 /// <param name="mkH">补充单元格高度</param>
455 /// <param name="fillCell">自动补行的单元格</param>
456 private void DrawTD(Graphics g, Cell tdCell, float setX, float setY, bool isMakeup, float mkH, bool fillCell)
457 {
458 #region 参数变量
459
460 Pen pen;
461 Brush brush;
462
463 // 获取单元格绘制坐标矩形信息
464 float tdX = tdCell.RectX + setX;
465 float tdY = setY;
466 float tdW = tdCell.RectW;
467 float tdH = 0;
468
469 if (fillCell)
470 {
471 tdH = 21 * Zoom; // 自动补行的单元格的高度固定为21px
472 }
473 else
474 {
475 if (isMakeup) // 补充单元格
476 {
477 tdH = mkH;
478 tdY = tdY + HeadPix; // 如果是补充单元格,则此单元格的Y坐标:如果每页打印标题或表头,则Y坐标 需要下移 HeadPix
479 }
480 else // 实际单元格
481 {
482 tdH = tdCell.RectH;
483 }
484 if (tdCell.RowSpan > 1) // 判定单元格高度是否超过底线
485 {
486 tdH = Calc_CellOverHeight(tdCell, tdY, tdH);
487 }
488 }
489
490 #endregion
491
492 #region 绘制背景
493
494 // 填充颜色
495 brush = new SolidBrush(tdCell.BackColor);
496 g.FillRectangle(brush, tdX + 1.0f * Zoom, tdY + 1.0f * Zoom, tdW - 2.0f * Zoom, tdH - 2.0f * Zoom);
497
498 #endregion
499
500 #region 绘制边框
501
502 // 左边框线
503 if (tdCell.LeftBorder.LineWidth > 0)
504 {
505 pen = new Pen(tdCell.LeftBorder.LineColor);
506 pen.DashStyle = tdCell.LeftBorder.LineDash;
507 pen.Width = tdCell.LeftBorder.LineWidth;
508 g.DrawLine(pen, tdX, tdY, tdX, tdY + tdH);
509 }
510
511 // 上边框线
512 if (tdCell.TopBorder.LineWidth > 0)
513 {
514 pen = new Pen(tdCell.TopBorder.LineColor);
515 pen.DashStyle = tdCell.TopBorder.LineDash;
516 pen.Width = tdCell.TopBorder.LineWidth;
517 g.DrawLine(pen, tdX, tdY, tdX + tdW, tdY);
518 }
519
520 // 右边框线
521 if (tdCell.RightBorder.LineWidth > 0)
522 {
523 pen = new Pen(tdCell.RightBorder.LineColor);
524 pen.DashStyle = tdCell.RightBorder.LineDash;
525 pen.Width = tdCell.RightBorder.LineWidth;
526 g.DrawLine(pen, tdX + tdW, tdY, tdX + tdW, tdY + tdH);
527 }
528
529 // 下边框线
530 if (tdCell.BottomBorder.LineWidth > 0)
531 {
532 pen = new Pen(tdCell.BottomBorder.LineColor);
533 pen.DashStyle = tdCell.BottomBorder.LineDash;
534 pen.Width = tdCell.BottomBorder.LineWidth;
535 g.DrawLine(pen, tdX, tdY + tdH, tdX + tdW, tdY + tdH);
536 }
537
538 #endregion
539
540 #region 绘制文字
541
542 if (!fillCell)
543 {
544 RectangleF rect = new RectangleF(tdX, tdY, tdW, tdH);
545 if (tdCell.IsImage)
546 {
547 this.DrawImg(g, rect, tdCell.ImageUrl);
548 }
549 else
550 {
551 brush = new SolidBrush(tdCell.FontColor);
552 this.DrawStr(g, rect, brush, tdCell.CellFont, tdCell.strFormat, tdCell.Value);
553 }
554 }
555
556 #endregion
557 }
558
559 /// <summary>
560 /// 绘制字符串
561 /// 溢出时,换行缩小字符
562 /// 字体缩小到的最小值不得小于
563 /// </summary>
564 /// <param name="g">绘图对象</param>
565 /// <param name="strRect">文本区域</param>
566 /// <param name="strBrush">文本笔画</param>
567 /// <param name="strFont">文本字体</param>
568 /// <param name="strFormat">文本格式</param>
569 /// <param name="strValue">文本字符</param>
570 /// <returns></returns>
571 private void DrawStr(Graphics g, RectangleF strRect, Brush strBrush, Font strFont, StringFormat strFormat, string strValue)
572 {
573 // 报表设置:字符溢出不做处理
574 if (!this.IsOverFlow)
575 {
576 g.DrawString(strValue, strFont, strBrush, strRect, strFormat);
577 }
578 else // 需要处理
579 {
580 // 测量字体的宽度和高度 会发现误差很大,如果一个一个的测量,误差就实在太大,所以这里就用简单的方式来进行处理
581 SizeF sf = g.MeasureString(strValue, strFont); // 此种方式测量误差很大,如果
582 if (strRect.Width > sf.Width)
583 {
584 g.DrawString(strValue, strFont, strBrush, strRect, strFormat);
585 }
586 else
587 {
588 // 计算换行后字符的全部高度是否满足
589 int maxLines = 0; // 计算当前字符当前字体最大打印的行数
590 maxLines = (int)Math.Ceiling((double)sf.Width / (double)strRect.Width);
591 if (strRect.Height >= maxLines * sf.Height)
592 {
593 g.DrawString(strValue, strFont, strBrush, strRect, strFormat);
594 }
595 else
596 {
597 float tmScale = strRect.Height / (maxLines * sf.Height);
598 Font tmNewFont = new Font(strFont.Name, strFont.Size * tmScale, strFont.Style, GraphicsUnit.Point);
599 g.DrawString(strValue, tmNewFont, strBrush, strRect, strFormat);
600 }
601 }
602 }
603
604 }
605
606 /// <summary>
607 /// 绘制图片
608 /// 将Base64图片流字符串转换成图片并进行绘制
609 /// </summary>
610 /// <param name="g"></param>
611 /// <param name="strRect"></param>
612 /// <param name="base64Img"></param>
613 private void DrawImg(Graphics g, RectangleF strRect, string base64Img)
614 {
615 if (base64Img.Trim() == "") return;
616 string imgStr = base64Img.Replace("data:image/gif;base64,", "").Trim();
617 if (imgStr == "") return;
618
619 // 生成图片
620 try
621 {
622 MemoryStream stream = new MemoryStream(Convert.FromBase64String(imgStr));
623 Bitmap picImg = new Bitmap(stream);
624
625 RectangleF imgRectF = new RectangleF(0f, 0f, (float)picImg.Width, (float)picImg.Height); // 原始图片矩形
626 RectangleF newRectF = new RectangleF(strRect.X + 1f, strRect.Y + 1f, (float)strRect.Width - 2f, (float)strRect.Height - 2f); // 绘制图片矩形
627 g.DrawImage(picImg, newRectF, imgRectF, GraphicsUnit.Pixel); // 绘制缩放图片
628 stream.Close();
629 }
630 catch
631 {
632 return;
633 }
634 }
635
636 /// <summary>
637 /// 绘制线条
638 /// </summary>
639 /// <param name="g">绘图对象</param>
640 /// <param name="start_X">开始X</param>
641 /// <param name="start_Y">开始Y</param>
642 /// <param name="end_X">结束X</param>
643 /// <param name="end_Y">结束Y</param>
644 private void DrawLine(Graphics g, float start_X, float start_Y, float end_X, float end_Y)
645 {
646 Pen linePen = new Pen(Color.Black, 1.0f);
647 linePen.DashStyle = DashStyle.Solid;
648 g.DrawLine(linePen, start_X, start_Y, end_X, end_Y);
649 }
650
651 private float ChangeUnit(float vSize)
652 {
653 return (vSize * 72f / 96f * 72f / 75f);
654 }
655
656 /// <summary>
657 /// 获取行对象
658 /// </summary>
659 /// <param name="rowIndex"></param>
660 /// <returns></returns>
661 private Row GetRow(int rowIndex)
662 {
663 foreach (Row retRow in _rowsList)
664 {
665 if (retRow.RowIndex == rowIndex)
666 return retRow;
667 }
668 return null;
669 }
670
671 /// <summary>
672 /// 获取分页页面
673 /// </summary>
674 /// <param name="pNo">页码</param>
675 /// <returns></returns>
676 private PagingItem GetPageItem(int pNo)
677 {
678 foreach (PagingItem retPItem in PageList)
679 {
680 if (retPItem.PageNum == pNo)
681 return retPItem;
682 }
683
684 return null;
685 }
686
687 /// <summary>
688 /// 计算绘制高度
689 /// 判定并且计算单元格高度是否超过当前页面所有行高度的底线
690 /// </summary>
691 /// <param name="mCell">单元格</param>
692 /// <param name="mY">Y 轴坐标值</param>
693 /// <param name="mH">H 当前高度</param>
694 /// <returns></returns>
695 private float Calc_CellOverHeight(Cell mCell, float mY, float mH)
696 {
697 float returnHeight = 0; // 返回高度
698 float tm_AllTrHeight = GetThisPageDataRowsHeight(); // 当前页面内所有数据行的高度
699 float tm_RealY = 0; // 相对最大Y值
700 float tm_AbsY = 0; // 实际最大Y值
701 float tm_OverPlus = 0; // 单元格剩余高度
702 tm_RealY = mY + mH; // 实际最大Y值
703 if (IsAllPrintFoot) // 每页打印表尾
704 tm_AbsY = ReptRect.Y + (tm_AllTrHeight - FootPix); // 需要减去表尾高度
705 else
706 tm_AbsY = tm_AllTrHeight + ReptRect.Y;
707
708 if (tm_RealY > tm_AbsY)
709 {
710 returnHeight = tm_AbsY - mY; // 当前页面实际最大高度-单元格的当前Y坐标值 = 返回单元格在本页内需要绘制的高度
711 tm_OverPlus = mH - returnHeight; // 当前高度-单元格当前页面需要绘制的高度=下页需要绘制的补充高度
712
713 // 将当前单元格添加到后页需要补充绘制数组中去
714 PagingItem nPageItem = GetPageItem(CurPageNum);
715 PagingMakeUp nMakeUp = new PagingMakeUp();
716 nMakeUp.MakeupCell = mCell;
717 nMakeUp.MakeupHeight = tm_OverPlus;
718 nPageItem.MakeupList.Add(nMakeUp);
719 }
720 else
721 {
722 returnHeight = mH;
723 }
724
725 return returnHeight;
726 }
727
728 /// <summary>
729 /// 获取本页内所有数据行的高度
730 /// </summary>
731 /// <returns></returns>
732 private float GetThisPageDataRowsHeight()
733 {
734 float retHeight = 0;
735 PagingItem oThisPage = GetPageItem(CurPageNum); // 当前页
736
737 foreach (int oRowIndex in oThisPage.IndexList)
738 {
739 Row oThisRow = GetRow(oRowIndex);
740 retHeight += oThisRow.RowHeight;
741 }
742
743 return retHeight;
744 }
745
746 /// <summary>
747 /// 获取页内某一项所属行的高度
748 /// </summary>
749 /// <param name="itemPage">页面对象</param>
750 /// <param name="itemIndex">本页行数组中的某一项的序号</param>
751 /// <returns></returns>
752 private float GetThisPageOneRowHeight(PagingItem itemPage, int itemIndex)
753 {
754 float retHeight = 0;
755 if (itemIndex < itemPage.IndexList.Count && itemIndex >= 0)
756 {
757 Row oThisRow = GetRow(itemPage.IndexList[itemIndex]);
758 retHeight = oThisRow.RowHeight;
759 }
760 return retHeight;
761 }
762
763 #endregion
764
765 }
766 }
3、PagingCalc 分页计算类
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Drawing;
5
6 namespace E_Print
7 {
8 /// <summary>
9 /// 分页计算
10 /// </summary>
11 public class PagingCalc
12 {
13 #region 私有变量
14
15 /// <summary>
16 /// 表格区域
17 /// </summary>
18 private RectangleF _tableRect;
19
20 /// <summary>
21 /// 报表行集
22 /// </summary>
23 private List<Row> _rowsList;
24
25 /// <summary>
26 /// 是否每页打印标题
27 /// </summary>
28 private bool _isAllPrintTitle;
29
30 /// <summary>
31 /// 是否每页打印表头
32 /// </summary>
33 private bool _isAllPrintHead;
34
35 /// <summary>
36 /// 是否每页打印表尾
37 /// </summary>
38 private bool _isAllPrintFoot;
39
40 /// <summary>
41 /// 标题行集
42 /// </summary>
43 private List<Row> TitleList;
44
45 /// <summary>
46 /// 表头前行集
47 /// </summary>
48 private List<Row> HForeList;
49
50 /// <summary>
51 /// 表头行集
52 /// </summary>
53 private List<Row> HeadList;
54
55 /// <summary>
56 /// 数据行集
57 /// </summary>
58 private List<Row> DataList;
59
60 /// <summary>
61 /// 表尾行集
62 /// </summary>
63 private List<Row> FootList;
64
65 /// <summary>
66 /// 每页打印标题+表头高度
67 /// </summary>
68 private float _myHeadPix;
69
70 /// <summary>
71 /// 每页打印表尾高度
72 /// </summary>
73 private float _myFootPix;
74
75 #endregion
76
77 #region 构造方法
78
79 /// <summary>
80 /// 构造函数
81 /// </summary>
82 public PagingCalc()
83 {
84 _tableRect = new RectangleF();
85 _rowsList = new List<Row>();
86
87 _isAllPrintTitle = false;
88 _isAllPrintHead = false;
89 _isAllPrintFoot = false;
90
91 TitleList = new List<Row>();
92 HForeList = new List<Row>();
93 HeadList = new List<Row>();
94 DataList = new List<Row>();
95 FootList = new List<Row>();
96
97 _myHeadPix = 0;
98 _myFootPix = 0;
99 }
100
101 #endregion
102
103 #region 属性方法
104
105 /// <summary>
106 /// 获取--设置--表格区域
107 /// </summary>
108 public RectangleF TableRect
109 {
110 get { return _tableRect; }
111 set { _tableRect = value; }
112 }
113
114 /// <summary>
115 /// 获取--设置--表格行集
116 /// </summary>
117 public List<Row> RowsList
118 {
119 get { return _rowsList; }
120 set { _rowsList = value; }
121 }
122
123 /// <summary>
124 /// 获取--设置--是否每页打印标题
125 /// </summary>
126 public bool IsAllPrintTitle
127 {
128 get { return _isAllPrintTitle; }
129 set { _isAllPrintTitle = value; }
130 }
131
132 /// <summary>
133 /// 获取--设置--是否每页打印表头
134 /// </summary>
135 public bool IsAllPrintHead
136 {
137 get { return _isAllPrintHead; }
138 set { _isAllPrintHead = value; }
139 }
140
141 /// <summary>
142 /// 获取--设置--是否每页打印表尾
143 /// </summary>
144 public bool IsAllPrintFoot
145 {
146 get { return _isAllPrintFoot; }
147 set { _isAllPrintFoot = value; }
148 }
149
150 /// <summary>
151 /// 获取--设置--每页打印标题+表头高度
152 /// </summary>
153 public float MyHeadPix
154 {
155 get { return _myHeadPix; }
156 set { _myHeadPix = value; }
157 }
158
159 /// <summary>
160 /// 获取--设置--每页打印表尾巴高度
161 /// </summary>
162 public float MyFootPix
163 {
164 get { return _myFootPix; }
165 set { _myFootPix = value; }
166 }
167
168 #endregion
169
170 #region 计算方法
171
172 /// <summary>
173 /// 分页计算
174 /// </summary>
175 /// <returns></returns>
176 public List<PagingItem> CalcPages()
177 {
178 List<PagingItem> retPages = new List<PagingItem>();
179
180 // 无需分页
181 if (Get_TableAllHeight() <= TableRect.Height)
182 {
183 PagingItem tmItem0 = new PagingItem();
184 tmItem0.PageNum = 1;
185 for (int y = 0; y < RowsList.Count; y++)
186 {
187 tmItem0.IndexList.Add(y);
188 }
189 retPages.Add(tmItem0);
190 }
191 else // 需要分页
192 {
193 // 有设置了 每页打印标题、表头、表位 其中的任意一个
194 if (Get_IsCusSet_THDF()) // 则执行每页相对分页
195 {
196 Paging_Relative(0, ref retPages);
197
198 // 计算每页打印头尾高度
199 MyHeadPix = 0;
200 if (IsAllPrintTitle)
201 {
202 MyHeadPix += Get_TableTileHeight();
203 }
204
205 if (IsAllPrintHead)
206 {
207 MyHeadPix += Get_TableHeadHeight();
208 }
209
210 if (IsAllPrintFoot)
211 {
212 MyFootPix = Get_TableFootHeight();
213 }
214 }
215 else // 执行直接数据分页
216 {
217 Paging_Direct(0, ref retPages);
218 }
219 }
220
221 return retPages;
222 }
223
224 /// <summary>
225 /// 直接分页
226 /// </summary>
227 /// <param name="startR">开始行号</param>
228 /// <param name="pages">页面数组</param>
229 private void Paging_Direct(int startR, ref List<PagingItem> pages)
230 {
231 float p_Height = TableRect.Height;
232 PagingItem p_Item = new PagingItem();
233 p_Item.PageNum = pages.Count + 1;
234 for (int t = startR; t < RowsList.Count; t++)
235 {
236 // 检查行内单元格是否不允许分页两种情况:条形码,图片
237 if (Paging_CheckCell(RowsList[t], p_Height))
238 {
239 startR = t;
240 pages.Add(p_Item);
241 Paging_Direct(startR, ref pages);
242 break;
243 }
244 else
245 {
246 p_Height -= RowsList[t].RowHeight;
247 if (p_Height <= 0)
248 {
249 startR = t;
250 pages.Add(p_Item);
251 Paging_Direct(startR, ref pages);
252 break;
253 }
254 else
255 {
256 p_Item.IndexList.Add(t);
257 if (t == RowsList.Count - 1)
258 {
259 pages.Add(p_Item);
260 }
261 }
262 }
263 }
264 }
265
266 /// <summary>
267 /// 相对分页
268 /// </summary>
269 /// <param name="startR">开始序号</param>
270 /// <param name="pages">页面数组</param>
271 private void Paging_Relative(int startR, ref List<PagingItem> pages)
272 {
273 SplitReportArea(); // 拆分表行
274 float p_Height = TableRect.Height; // 页面总高
275 PagingItem p_Item = new PagingItem(); // 分页页面
276 p_Item.PageNum = pages.Count + 1; // 分页页码
277 bool runNext = false; // 继续分页
278
279 #region 每页打印标题
280
281 // 每页打印标题
282 if (IsAllPrintTitle)
283 {
284 p_Height -= Get_TableTileHeight();
285 foreach (Row p_Row in TitleList)
286 p_Item.IndexList.Add(p_Row.RowIndex);
287 }
288 else
289 {
290 if (p_Item.PageNum == 1) // 第一页特殊处理
291 {
292 p_Height -= Get_TableTileHeight();
293 foreach (Row p_Row in TitleList)
294 p_Item.IndexList.Add(p_Row.RowIndex);
295 }
296 }
297
298 #endregion
299
300 #region 每页打印表头
301
302 // 每页打印表头
303 if (IsAllPrintHead)
304 {
305 if (p_Item.PageNum == 1) // 第一页特殊处理
306 {
307 // 计算表头前的行高
308 p_Height -= Get_TableHForHeight();
309 foreach (Row p_Row in HForeList)
310 p_Item.IndexList.Add(p_Row.RowIndex);
311 }
312
313 // 计算表头行的高度
314 p_Height -= Get_TableHeadHeight();
315 foreach (Row p_Row in HeadList)
316 p_Item.IndexList.Add(p_Row.RowIndex);
317 }
318 else
319 {
320 if (p_Item.PageNum == 1) // 第一页特殊处理
321 {
322 // 计算表头前的行高
323 p_Height -= Get_TableHForHeight();
324 foreach (Row p_Row in HForeList)
325 p_Item.IndexList.Add(p_Row.RowIndex);
326
327 // 计算表头行的高度
328 p_Height -= Get_TableHeadHeight();
329 foreach (Row p_Row in HeadList)
330 p_Item.IndexList.Add(p_Row.RowIndex);
331 }
332 }
333
334 #endregion
335
336 #region 每页数据区域
337
338 // 每页数据划分
339 if (IsAllPrintFoot)
340 {
341 p_Height -= Get_TableFootHeight(); // 表格高度 先减去表尾的高度
342 }
343 for (int t = startR; t < DataList.Count; t++)
344 {
345 // 检查行内单元格是否不允许分页两种情况:条形码,图片
346 if (Paging_CheckCell(DataList[t], p_Height)) // 此情况下,单元格不能分割,并且高度超过页面剩余高度,所以要启动新的一页
347 {
348 startR = t;
349 runNext = true;
350 break;
351 }
352 else
353 {
354 p_Height -= DataList[t].RowHeight;
355 if (p_Height <= 0)
356 {
357 startR = t;
358 runNext = true;
359 break;
360 }
361 else
362 {
363 p_Item.IndexList.Add(DataList[t].RowIndex);
364 }
365 }
366 }
367
368 #endregion
369
370 #region 每页打印表尾
371
372 // 每页打印表尾
373 if (IsAllPrintFoot)
374 {
375 foreach (Row p_Row in FootList)
376 p_Item.IndexList.Add(p_Row.RowIndex);
377 }
378
379 #endregion
380
381 #region 添加分页页面
382
383 pages.Add(p_Item);
384 if (runNext)
385 {
386 Paging_Relative(startR, ref pages);
387 }
388
389 #endregion
390 }
391
392 /// <summary>
393 /// 检查行内单元格如果是图片
394 /// 并且合并行数大于1
395 /// </summary>
396 /// <param name="cRow"></param>
397 /// <param name="cHeight"></param>
398 /// <returns></returns>
399 private bool Paging_CheckCell(Row cRow, float cHeight)
400 {
401 foreach (Cell cCell in cRow.RowCells)
402 {
403 if (cCell.IsImage == true)
404 {
405 if (cCell.RectH > cHeight)
406 return true;
407 }
408 }
409 return false;
410 }
411
412 #endregion
413
414 #region 辅助方法
415
416 /// <summary>
417 /// 获取--报表全部高度
418 /// </summary>
419 /// <returns></returns>
420 private float Get_TableAllHeight()
421 {
422 float retHight = 0;
423 for (int k = 0; k < RowsList.Count; k++)
424 {
425 Row t_Row = RowsList[k];
426 retHight += t_Row.RowHeight;
427 }
428 return retHight;
429 }
430
431 /// <summary>
432 /// 获取是否设置了标题、表头、表尾 中的任意一个
433 /// </summary>
434 /// <returns></returns>
435 private bool Get_IsCusSet_THDF()
436 {
437 string tmType = "";
438 foreach (Row cusRow in this.RowsList)
439 {
440 tmType = cusRow.RowType.ToLower().Trim();
441 if (tmType == "t" || tmType == "h" || tmType == "f")
442 return true;
443 }
444
445 return false;
446 }
447
448 /// <summary>
449 /// 获取--报表标题高度
450 /// </summary>
451 /// <returns></returns>
452 private float Get_TableTileHeight()
453 {
454 float retHight = 0;
455 for (int k = 0; k < TitleList.Count; k++)
456 retHight += TitleList[k].RowHeight;
457
458 return retHight;
459 }
460
461 /// <summary>
462 /// 获取--报表表头前高度
463 /// </summary>
464 /// <returns></returns>
465 private float Get_TableHForHeight()
466 {
467 float retHight = 0;
468 for (int k = 0; k < HForeList.Count; k++)
469 retHight += HForeList[k].RowHeight;
470
471 return retHight;
472 }
473
474 /// <summary>
475 /// 获取--报表表头高度
476 /// </summary>
477 /// <returns></returns>
478 private float Get_TableHeadHeight()
479 {
480 float retHight = 0;
481 for (int k = 0; k < HeadList.Count; k++)
482 retHight += HeadList[k].RowHeight;
483 return retHight;
484 }
485
486 /// <summary>
487 /// 获取--报表表尾高度
488 /// </summary>
489 /// <returns></returns>
490 private float Get_TableFootHeight()
491 {
492 float retHight = 0;
493 for (int k = 0; k < FootList.Count; k++)
494 retHight += FootList[k].RowHeight;
495 return retHight;
496 }
497
498 /// <summary>
499 /// 拆分报表区域
500 /// </summary>
501 public void SplitReportArea()
502 {
503 TitleList = new List<Row>();
504 HForeList = new List<Row>();
505 HeadList = new List<Row>();
506 DataList = new List<Row>();
507 FootList = new List<Row>();
508
509 for (int m = 0; m < RowsList.Count; m++)
510 {
511 Row mmRow = RowsList[m];
512 switch (mmRow.RowType.ToLower())
513 {
514 case "t": // 标题
515 TitleList.Add(mmRow);
516 break;
517 case "h": // 表头
518 HeadList.Add(mmRow);
519 break;
520 case "f": // 表尾
521 FootList.Add(mmRow);
522 break;
523 case "d": // 数据
524 default:
525 DataList.Add(mmRow);
526 break;
527 }
528 }
529
530
531 // 设置表头前行集
532 if (TitleList.Count == 0 && HeadList.Count > 0)
533 {
534 List<Row> tmpList = new List<Row>();
535 for (int n = 0; n < DataList.Count; n++)
536 {
537 if (DataList[n].RowIndex < HeadList[0].RowIndex)
538 {
539 HForeList.Add(DataList[n]);
540 tmpList.Add(DataList[n]);
541 }
542 }
543
544 for (int n = 0; n < tmpList.Count; n++)
545 {
546 DataList.Remove(tmpList[n]);
547 }
548
549 tmpList.Clear();
550 }
551
552 // 重设表尾 不是每页打印表尾情况下,那么表位就去掉
553 if (!IsAllPrintFoot)
554 {
555 foreach (Row tRow in FootList)
556 DataList.Add(tRow);
557 FootList.Clear();
558 }
559 }
560
561 #endregion
562 }
563 }
4、PagingMakeUp 分页补充绘制类
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace E_Print
6 {
7 /// <summary>
8 /// 下页需要补充绘制
9 /// </summary>
10 public class PagingMakeUp
11 {
12 /// <summary>
13 /// 补充单元格
14 /// </summary>
15 private Cell _makeupCell;
16
17 /// <summary>
18 /// 补充高度
19 /// </summary>
20 private float _makeupHeight;
21
22 /// <summary>
23 /// 构造函数
24 /// </summary>
25 public PagingMakeUp()
26 {
27 _makeupCell = new Cell();
28 _makeupHeight = 0;
29 }
30
31 /// <summary>
32 /// 获取--设置--补充单元格
33 /// </summary>
34 public Cell MakeupCell
35 {
36 get { return _makeupCell; }
37 set { _makeupCell = value; }
38 }
39
40 /// <summary>
41 /// 获取--设置--补充高度
42 /// </summary>
43 public float MakeupHeight
44 {
45 get { return _makeupHeight; }
46 set { _makeupHeight = value; }
47 }
48
49 }
50 }
5、IObjectSafety 抽象接口类
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Runtime.InteropServices;
5
6 namespace E_Print
7 {
8 /// <summary>
9 /// 接口抽象基类
10 /// </summary>
11 [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
12 [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
13 public interface IObjectSafety
14 {
15 [PreserveSig]
16 int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
17
18 [PreserveSig()]
19 int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
20 }
21 }
6、预览效果

7、我们可以通过源码中的 EPrintTest.exe 打印Winform 实例 ,来执行示范,
通过WEB前端js 生成打印的TABLE的 RptData.xml格式 数据,在WINForm中直接使用
如果在网页中,通过JS 直接传给打印控件就OK
Mikel
