www.pudn.com > Cnewprint.rar > MisPrinter.cs
using System;
using System.Drawing;
using System.Drawing.Printing;
namespace GoldPrinter
{
///
/// 本程序为通用打印程序,单据、会计凭证、发票清单、报表、任意复杂表格、合并表格如工矿企业合同都可以由系统提供的几个默
/// 认打印对象组合打印。
/// DataGrid、DataTable、MSHFlexGrid等二维形式全部可以打印。
/// 部分对象如PrinterMargins、Sewing、GridLineFlag、GridMergeFlag等提供图例,以促进理解。
/// 后期版本将提供XML描述、SQL数据源的打印,并用管理器管理任意多个网格、文本对象、图象等,用户可以随意定义。
///
/// 程序提供:周方勇;Email:flygoldfish@sina.com。
/// 请 关 注:WebMIS.Net快速开发工具,不写一行程序开发B/S架构下MIS、OA、CRM、人事管理、档案管理等数据库网页系统。简单、实用、稳定、可靠。
/// 下 载:
/// 上海奥联:WWW.AlinkSoft.COM
/// 用友华表:WWW.CellSoft.CC
///★★★★★您可以免费使用此程序,但是请您保留此说明,以维护知识产权★★★★★
///
public class MisPrinter:IDisposable
{
public Color BackColor = Color.White;//背景颜色
//绘图表面
private Graphics mGraphics;
//打印文档
private PrintDocument mPrintDocument;
//下一对象的起点坐标及宽
private float X,Y,Width;
//翻页用
private int mCurrentPageIndex; //当前页
private int mCurrentRowIndex; //主数据网格的当前行
private int mCurrentRowIndexForFooter; //Footer当前行
//字段
private int _rowsPerPage; //每页行数,小于等于0自适应,默认
private bool _isSewingLine; //是否打印装订线(默认无)
private bool _isPrinterMargins; //是否打印有效区域矩阵(默认无)
private bool _isSubTotalPerPage; //是否每页都要显示主数据网格当前页小计(默认否)
private string _subTotalCol; //每页小计要指定的列
private Sewing _sewing; //装订,对象的线长小于0则自动设置
private GridBorderFlag _gridBorder; //网格边框
#region 字段属性
///
/// 每页行数,小于等于0自适应,默认
///
public int RowsPerPage
{
get
{
return _rowsPerPage;
}
set
{
int mint = value;
if (mint < 0)
{
mint = -1;
}
_rowsPerPage = mint;
}
}
///
/// 是否打印装订线,对象的线长小于0则自动设置
///
public bool IsSewingLine
{
get
{
return _isSewingLine;
}
set
{
_isSewingLine = value;
}
}
///
/// 是否打印有效区域矩阵
///
public bool IsPrinterMargins
{
get
{
return _isPrinterMargins;
}
set
{
_isPrinterMargins = value;
}
}
///
/// 是否每页都要显示当前页小计(默认否)
///
public bool IsSubTotalPerPage
{
get
{
return _isSubTotalPerPage;
}
set
{
_isSubTotalPerPage = value;
}
}
///
/// 用分号分隔的要每页小计列
///
public string SubTotalCol
{
get
{
return _subTotalCol;
}
set
{
_subTotalCol = value;
}
}
///
/// 装订对象,对象的线长小于0则自动设置
///
public Sewing Sewing
{
get
{
return this._sewing;
}
set
{
if (value != null)
{
this._sewing = value;
}
else
{
this._sewing.Margin = 0; //宽度为0则不打印
}
}
}
///
/// 网格边框
///
public GridBorderFlag GridBorder
{
get
{
return this._gridBorder;
}
set
{
this._gridBorder = value;
}
}
#endregion
//********************打印对象********************
private Title _title; //主标题
private Caption _caption; //副标题
private Top _top; //简单的一行三列打印样式,第一列居左,第三列居右,中间列居中
private Header _header; //正文网格主体之上的几行几列的标注说明
private MultiHeader _multiHeader; //正文网格主体标题头可能需要多层合并表头说明
private Body _body; //*正文网格主体,必须,打印以此为基准
protected Footer _footer; //正文网格主体之下的几行几列的标注说明
private Bottom _bottom; //简单的一行三列打印样式,第一列居左,第三列居右,中间列居中
#region 打印对象字段属性
#region Title、Caption
///
/// 获取或设置打印主标题,可以是文本,也可以是定义更多特性的Title对象
///
public object Title
{
get
{
return this._title;
}
set
{
if (value != null)
{
if (value.GetType().ToString() == "System.String")
{
if (this._title == null)
{
this._title = new Title();
}
this._title.Text = (string)value;
}
else if(value.GetType().ToString() == "GoldPrinter.Title")
{
this._title = (GoldPrinter.Title)value;
}
}
}
}
///
/// 获取或设置打印副标题,可以是文本,也可以是定义更多特性的Caption对象
///
public object Caption
{
get
{
return this._caption;
}
set
{
if (value != null)
{
if (value.GetType().ToString() == "System.String")
{
if (this._caption == null)
{
this._caption = new Caption();
}
this._caption.Text = (string)value;
}
else if(value.GetType().ToString() == "GoldPrinter.Caption")
{
this._caption = (GoldPrinter.Caption)value;
}
}
}
}
#endregion
#region 或取或设置网格头、底,可以是以'|'分隔的字符串或或一维数组或具有更多特性的Top/Bottom对象
///
/// 或取或设置网格头,可以是以'|'分隔的字符串或或一维数组或具有更多特性的Top对象
///
public object Top
{
get
{
return this._top;
}
set
{
if (value != null)
{
if (value.GetType().ToString() == "System.String" || value.GetType().ToString() == "System.String[]")
{
if (this._top == null)
{
this._top = new Top();
}
this._top.DataSource = value;
}
else if(value.GetType().ToString() == "GoldPrinter.Top")
{
this._top = (GoldPrinter.Top)value;
}
}
}
}
///
/// 或取或设置网格底,可以是以'|'分隔的字符串或或一维数组或具有更多特性的Bottom对象
///
public object Bottom
{
get
{
return this._bottom;
}
set
{
if (value != null)
{
if (value.GetType().ToString() == "System.String" || value.GetType().ToString() == "System.String[]")
{
if (this._bottom == null)
{
this._bottom = new Bottom();
}
this._bottom.DataSource = (string)value;
}
else if(value.GetType().ToString() == "GoldPrinter.Bottom")
{
this._bottom = (GoldPrinter.Bottom)value;
}
}
}
}
#endregion
public object Header
{
get
{
return _header;
}
set
{
this._header = (GoldPrinter.Header)value;
}
}
public object MultiHeader
{
get
{
return _multiHeader;
}
set
{
this._multiHeader = (GoldPrinter.MultiHeader)value;
}
}
public object Body
{
get
{
return _body;
}
set
{
_body = (GoldPrinter.Body)value;
}
}
public object Footer
{
get
{
return this._footer;
}
set
{
this._footer = (GoldPrinter.Footer)value;
}
}
#endregion
//还可以将此程序稍微修改,用一个集体管理,动态加载打印对象,形成任意多个网格的组合体,打印任意复杂的网格
public MisPrinter()
{
mCurrentPageIndex = 1;
_rowsPerPage = 0;
mCurrentRowIndex = 0;
mCurrentRowIndexForFooter = 0;
_isSewingLine = false;
_isPrinterMargins = false;
_isSubTotalPerPage = false;
_subTotalCol = "";
_sewing = new Sewing(0,SewingDirectionFlag.Left);
mPrintDocument = new PrintDocument();
_body = new Body(); //主要对象,所以实例化
_gridBorder = GridBorderFlag.Double;
}
#region IDisposable 成员
public virtual void Dispose()
{
//...
}
#endregion
///
/// 获取或设置数据主体网格的数据源
///
public object DataSource
{
get
{
return this._body.DataSource;
}
set
{
this._body.DataSource = value;
}
}
///
/// 页面设置对话框,如果需要,国庆期间继续开放,敬请关注
///
public void PageSetup()
{
PrinterPageSetting printerPageSetting;
printerPageSetting = new PrinterPageSetting(mPrintDocument);
printerPageSetting.PrintPage += new PrintPageDelegate(this.PrintPageEventHandler);
printerPageSetting.ShowPageSetupDialog();
}
///
/// 打印,如果需要,国庆期间继续开放,敬请关注
///
public void Print()
{
PrinterPageSetting printerPageSetting;
printerPageSetting = new PrinterPageSetting(mPrintDocument);
printerPageSetting.PrintPage += new PrintPageDelegate(this.PrintPageEventHandler);
printerPageSetting.ShowPrintSetupDialog();
}
///
/// 打印预览,如果需要,国庆期间继续开放,敬请关注
///
public void Preview()
{
PrinterPageSetting printerPageSetting;
printerPageSetting = new PrinterPageSetting(mPrintDocument);
printerPageSetting.PrintPage += new PrintPageDelegate(this.PrintPageEventHandler);
printerPageSetting.ShowPrintPreviewDialog();
}
//绘制
private void PrintPageEventHandler(object obj,System.Drawing.Printing.PrintPageEventArgs ev)
{
Graphics g = ev.Graphics ;
this.mGraphics = g;
g.Clear(this.BackColor);
try
{
bool blnMore = this.Draw(g);
if (blnMore)
{
ev.HasMorePages = true;
mCurrentPageIndex++;
}
else
{
ev.HasMorePages = false;
this.mCurrentPageIndex = 1;
}
}
catch(Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
}
}
/// 对象打印接口
private void OutObject(IDraw outer)
{
// this.mGraphics.ResetTransform();
if (outer != null)
{
outer.Graphics = this.mGraphics;
outer.PrintDocument = this.mPrintDocument;
outer.Sewing = this.Sewing;
outer.RectangleF = new RectangleF(X,Y,Width,outer.Height);
outer.Draw();
this.Y += outer.RectangleF.Height;
}
}
#region 绘制过程
//*****这段代码确实太长了,应该用重构的手法进行处理,不过,我这里主要是让大家从头到尾的顺利的看下去
//*****在下一个版本的源代码中我会整理,大家也可以试一试。
private bool Draw(Graphics g)
{
bool blnHasMorePage = false; //是否还有下一页标记
if (this._body.Rows < 0)
{
throw new Exception("打印主要网格不能为空,请用Body设置!");
}
Printer printer = new Printer();
printer.Graphics = g;
printer.PrintDocument = this.mPrintDocument;
printer.Sewing = this.Sewing;
//初起打印起点坐标及打印区域的宽
Y = printer.PrinterMargins.Top;
X = printer.PrinterMargins.Left;
Width = printer.PrinterMargins.Width;
#region 画打印区域及装订线
if (IsPrinterMargins)
{
printer.DrawPrinterMargins();
}
if (IsSewingLine && _sewing.Margin > 0)
{
//对象的线长小于0则自动设置
if (this._sewing.LineLen < 0)
{
if (this._sewing.SewingDirection == SewingDirectionFlag.Left)
{
this._sewing.LineLen = printer.PageHeight;
}
else if (this._sewing.SewingDirection == SewingDirectionFlag.Top)
{
this._sewing.LineLen = printer.PageWidth;
}
}
printer.Sewing = this._sewing;
printer.DrawSewing();
}
#endregion
//正标题每页必重复打印,无需判断
if (_title != null)
{
OutObject(_title);
}
if (_caption != null && (mCurrentPageIndex == 1 || _caption.IsDrawAllPage))
{
if (_caption != null)
{
if (_title != null)
{
_caption.MoveY = this._title.Height + 5;
}
OutObject(_caption);
}
}
if (_title != null || _caption != null)
{
Y += 20; //标题与下面有一定距离
}
if (_top != null && (mCurrentPageIndex == 1 || _top.IsDrawAllPage))
{
OutObject(_top);
}
if (_header != null && (mCurrentPageIndex == 1 || _header.IsDrawAllPage))
{
OutObject(_header);
}
if (_title != null || _caption != null || _top.IsDrawAllPage || _header.IsDrawAllPage)
{
Y += 5; //网格与页头距离
}
if (_multiHeader != null && (mCurrentPageIndex == 1 || _multiHeader.IsDrawAllPage))
{
OutObject(_multiHeader);
}
#region 主体数据网格
//计算有效高度,便于分页
float validHeight = printer.PrinterMargins.Height - (Y - printer.PrinterMargins.Top);
if(_footer != null && _footer.IsDrawAllPage)
{
validHeight -= this._footer.Height;
}
if(_bottom != null && _bottom.IsDrawAllPage)
{
validHeight -= this._bottom.Height;
}
if (validHeight < 0)
{
throw new Exception("预留给打印主要网格的空间太小,请适当调整!");
}
//有效高度中当前页行数
int mRowsInCurPage = 0;
mRowsInCurPage = (int)(validHeight/(float)(this._body.RowHeight));
//如果指定每页行数,则以其为主
if (this.RowsPerPage > 0 && this.RowsPerPage < mRowsInCurPage)
{
mRowsInCurPage = this.RowsPerPage;
}
if (this.IsSubTotalPerPage)
{
mRowsInCurPage--;
}
//************以Body为主************
string[,] mArrGridText; //保留当前页文本,用于页小计
GoldPrinter.Body mbody;
//如果指定每页行数,则以其为主
if (this.RowsPerPage > 0 && this.RowsPerPage < mRowsInCurPage)
{
mbody = new Body(mRowsInCurPage,this._body.Cols);
}
else
{
//否则自适应
if (mRowsInCurPage > (this._body.Rows - this.mCurrentRowIndex))
{
mRowsInCurPage = this._body.Rows - this.mCurrentRowIndex;
}
mbody = new Body(mRowsInCurPage,this._body.Cols);
}
mbody.ColsAlignString = this._body.ColsAlignString;
//存当前页的二维文本
mArrGridText = new string[mRowsInCurPage,this._body.Cols];
for(int i = 0 ; i < mRowsInCurPage && mCurrentRowIndex < this._body.Rows ; i++)
{
for(int j = 0 ; j < this._body.Cols ; j++)
{
mArrGridText[i,j] = this._body.GetText(mCurrentRowIndex,j);
}
mCurrentRowIndex++;
}
mbody.GridText = mArrGridText;
OutObject(mbody);
//判断是否要分页,只要数据网格行数据大于数据网格行指针,则还有下一页
if (mCurrentRowIndex < this._body.Rows)
{
blnHasMorePage = true;
}
#region 打印每页小计,只需要将当前数组用循环累计就OK了,这段程序应专门重构为一个函数,读者可以自己试一试
if (_isSubTotalPerPage && _subTotalCol != "")
{
try
{
GoldPrinter.MultiHeader mhSubTotal = new MultiHeader(1,this._body.Cols);
mhSubTotal.Graphics = g;
mhSubTotal.PrintDocument = this.mPrintDocument;
mhSubTotal.Sewing = this._sewing;
mhSubTotal.RectangleF = new RectangleF(X,Y,Width,mhSubTotal.Height);
//循环
//....
mhSubTotal.SetText(0,0,"本页小计");
mhSubTotal.SetText(0,1,"本页小计");
string[] marrSubTotalCol = this._subTotalCol.Split(';');
Double mdblSubTotal = 0f;
int mintCol = 0;
for(int i = 0 ; i < marrSubTotalCol.Length ; i ++)
{
mintCol = int.Parse(marrSubTotalCol[i].Substring(0,1));
for(int j = 0 ; j < mArrGridText.GetLength(0) ; j++)
{
mdblSubTotal += Double.Parse(mArrGridText[j,mintCol]);
}
mhSubTotal.SetText(0,mintCol,mdblSubTotal.ToString());
}
mhSubTotal.Draw();
Y += mhSubTotal.Height;
}
catch(Exception e)
{}
}
#endregion
#endregion
Y += 5; //网格与页底距离
//打印页脚与最底
if (_footer != null)
{
if (blnHasMorePage == false || _footer.IsDrawAllPage)
{
//这里不再做判断了,读者自己对照Body的处理方法去试验,以加深理解,实际上应是注释的部分
OutObject(_footer);
/*
if (_footer.IsDrawAllPage)
{
OutObject(_footer);
}
else
{
//与Body同样的处理
}
*/
}
}
if (_bottom != null)
{
if (blnHasMorePage == false || _bottom.IsDrawAllPage)
{
if (_bottom.IsDrawAllPage)
{
OutObject(_bottom);
}
else
{
//计算有效高度
validHeight = printer.PrinterMargins.Height - (Y - printer.PrinterMargins.Top);
if (validHeight < _bottom.Height)
{
blnHasMorePage = true;
}
else
{
OutObject(_bottom);
}
}
}
}
//画边框
DrawBorder(g,this._multiHeader,mbody);
mbody = null;
return blnHasMorePage;
}
#endregion
private void DrawBorder(Graphics g,MultiHeader multiHeader,Body body)
{
//网格边框矩阵
RectangleF mrecGridBorder;
float x,y,width,height;
width = body.RectangleF.Width;
height = body.RectangleF.Height;
if (multiHeader != null)
{
x = multiHeader.RectangleF.X;
y = multiHeader.RectangleF.Y;
height += multiHeader.RectangleF.Height;
}
else
{
x = body.RectangleF.X;
y = body.RectangleF.Y;
}
if (this.IsSubTotalPerPage)
{
GoldPrinter.MultiHeader m = new MultiHeader(1,1);
height += m.RowHeight;
m = null;
}
mrecGridBorder = new RectangleF(x,y,width,height);
Pen pen = new Pen(Color.Black,1);
GoldPrinter.DrawRectangle dr = new DrawRectangle();
dr.Graphics = g;
dr.RectangleF = mrecGridBorder;
dr.Pen = pen;
switch (GridBorder)
{
case GridBorderFlag.Single:
dr.Draw();
break;
case GridBorderFlag.SingleBold:
dr.Pen.Width = 2;
dr.Draw();
if (multiHeader != null)
{
dr.RectangleF = body.RectangleF;
dr.DrawTopLine();
}
break;
case GridBorderFlag.Double:
dr.Draw();
mrecGridBorder = new RectangleF(x-2,y-2,width+4,height+4);
dr.RectangleF = mrecGridBorder;
dr.Draw();
break;
case GridBorderFlag.DoubleBold:
dr.Draw();
mrecGridBorder = new RectangleF(x-2,y-2,width+4,height+4);
dr.RectangleF = mrecGridBorder;
dr.Pen.Width = 2;
dr.Draw();
break;
}
}
#region 将打印的相关信息输出WriteMetricsToConsole(PrintPageEventArgs ev)
/*
public void WriteMetricsToConsole(PrintPageEventArgs ev)
{
Graphics g = ev.Graphics;
Console.WriteLine ("*****Information about the printer*****");
Console.WriteLine("纸张的大小 ev.PageSettings.PaperSize:" + ev.PageSettings.PaperSize);
Console.WriteLine("打印分辨率 ev.PageSettings.PrinterResolution:" + ev.PageSettings.PrinterResolution);
Console.WriteLine("旋转的角度 ev.PageSettings.PrinterSettings.LandscapeAngle" + ev.PageSettings.PrinterSettings.LandscapeAngle);
Console.WriteLine("");
Console.WriteLine ("*****Information about the page*****");
Console.WriteLine("页面的大小 ev.PageSettings.Bounds:" + ev.PageSettings.Bounds);
Console.WriteLine("页面(同上) ev.PageBounds:" + ev.PageBounds);
Console.WriteLine("页面的边距 ev.PageSettings.Margins.:" + ev.PageSettings.Margins);
Console.WriteLine("页面的边距 ev.MarginBounds:" + ev.MarginBounds);
Console.WriteLine("水平分辨率 ev.Graphics.DpiX:" + ev.Graphics.DpiX );
Console.WriteLine("垂直分辨率 ev.Graphics.DpiY:" + ev.Graphics.DpiY );
ev.Graphics.SetClip(ev.PageBounds);
Console.WriteLine("ev.Graphics.VisibleClipBounds:" + ev.Graphics.VisibleClipBounds);
SizeF drawingSurfaceSize = new SizeF(
ev.Graphics.VisibleClipBounds.Width * ev.Graphics.DpiX/100,
ev.Graphics.VisibleClipBounds.Height * ev.Graphics.DpiY/100);
Console.WriteLine("drawing Surface Size in Pixels" + drawingSurfaceSize);
}
*/
#endregion
}//End class
}//End Namespace