.net分页换行打印

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zx13525079024/article/details/84327802

.Net单据打印有很多方法,目前介绍一种完全画线,绘制文本的方法,效果图如下

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wms.Print.Service.Base;

namespace Wms.Print.Service.Grid
{
    /// <summary>
    /// 绘制网格,核心是二维数组,可以是DataGrid、MsHFlexGrid、DataTable、HtmlTable等二维表现形式的数据源。
    /// </summary>
    public class DrawGrid : MyGrid, IDraw, IDisposable
    {
        //************字    段************		
        private Graphics mGraphics;				//绘图表面
        private Rectangle mRectangle;			//绘制区

        //绘笔
        private Brush mBrush;
        private Pen mPen;

        #region IDraw 成员
        /// <summary>
        /// 获取或设置绘图表面
        /// </summary>
        public Graphics Graphics
        {
            get
            {
                return this.mGraphics;
            }
            set
            {
                this.mGraphics = value;
            }
        }

        /// <summary>
        /// 获取或设置绘制区域
        /// </summary>
        public Rectangle Rectangle
        {
            get
            {
                return mRectangle;
            }
            set
            {
                mRectangle = value;
            }
        }

        /// <summary>
        /// 画笔
        /// </summary>
        public Pen Pen
        {
            get
            {
                return mPen;
            }
            set
            {
                if (value != null)
                {
                    mPen = value;
                }
            }
        }

        /// <summary>
        /// 画刷
        /// </summary>
        public Brush Brush
        {
            get
            {
                return mBrush;
            }
            set
            {
                if (value != null)
                {
                    mBrush = value;
                }
            }
        }

        #endregion

        private Font[] mFonts;
        /// <summary>
        /// 网格各列的字体,仅对不合并的网格有效
        /// </summary>
        public Font[] Fonts
        {
            get { return mFonts; }
            set { mFonts = value; }
        }


        /// <summary>
        /// 
        /// </summary>
        public DrawGrid()
        {
            mPen = new Pen(Color.Black);
            mBrush = Brushes.Black;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="rows"></param>
        /// <param name="cols"></param>
        public DrawGrid(int rows, int cols)
        {
            this.Initialize(rows, cols);
        }
        /// <summary>
        /// 
        /// </summary>
        public override void Dispose()
        {
            base.Dispose();
            if (mGraphics != null)
                this.mGraphics.Dispose();
        }

        /// <summary>
        /// 绘制网格线,不包括边界线
        /// </summary>
        public void DrawGridLine()
        {
            DrawGridLine(this.mGraphics, this.mRectangle, this.Pen, this.GridText, this.PreferredRowHeight, this.ColsWidth, this.Line, this.Border, new PointF(1.0F, 1.0F), this.Merge);
        }

        /// <summary>
        /// 绘制网格文本
        /// </summary>
        public void DrawGridText()
        {
            DrawGridText(this.mGraphics, this.mRectangle, this.Brush, this.GridText, this.PreferredRowHeight, this.ColsWidth, this.ColsAlignString, this.Font, new PointF(1.0F, 1.0F), this.Merge);
        }

        /// <summary>
        /// 绘制边框
        /// </summary>
        public void DrawGridBorder()
        {
            DrawGridBorder(this.mGraphics, this.mRectangle, this.Pen, this.Border);
        }

        /// <summary>
        /// 绘制网格络及文本和边框
        /// </summary>
        public void Draw()
        {
            DrawGridLine();

            /*
            //测试绘制用的时间
            System.DateTime dt1;
            dt1 = System.DateTime.Now;
            Console.WriteLine(dt1.ToString() + dt1.Millisecond.ToString());
            */
            //______________________		
            DrawGridText();
            //______________________

            /*
            System.DateTime dt2;
            dt2 = System.DateTime.Now;
            Console.WriteLine(dt2.ToString() + dt2.Millisecond.ToString());

            TimeSpan aa = dt2 - dt1;
            double secondDef = aa.TotalSeconds;
            Console.WriteLine(secondDef.ToString());
            */
            DrawGridBorder();

        }

        #region	绘制核心

        #region 画标准横坚网格线核心 protected void DrawGridLine(Graphics g,Rectangle p_rec,int p_rows,int p_cols,int p_rowHeight,int[] p_arrColsWidth,GridLineFlag p_gridLineFlag,GridBorderFlag p_gridBorderFlag,PointF p_scaleXY)
        /// <summary>
        /// 画网格线,标准备的横竖线交叉的线
        /// </summary>
        /// <param name="g">绘图表面</param>
        /// <param name="p_rec">绘图区</param>
        /// <param name="pmPen">绘图线的笔,可以定义颜色与线宽</param>
        /// <param name="p_rows">行数</param>
        /// <param name="p_cols">列数</param>
        /// <param name="p_rowHeight">行高</param>
        /// <param name="p_arrColsWidth">列宽</param>
        /// <param name="p_gridLineFlag">网格线类型</param>
        /// <param name="p_gridBorderFlag">边框类型</param>
        /// <param name="p_scaleXY">水平与垂直方向缩放量</param>
        protected void DrawGridLine(Graphics g, Rectangle p_rec, Pen pmPen, int p_rows, int p_cols, int p_rowHeight, int[] p_arrColsWidth, GridLineFlag p_gridLineFlag, GridBorderFlag p_gridBorderFlag, PointF p_scaleXY)
        {
            //缩放矩阵,用于绘图
            Rectangle rec = new Rectangle(p_rec.X, p_rec.Y, p_rec.Width, p_rec.Height);

            //缩放程序
            this.TransGrid(g, rec, p_scaleXY);

            #region 有网格线才画
            if (p_gridLineFlag != GridLineFlag.None)
            {
                int lngRows = p_rows;	//arrStrGrid.GetLength(0);			//行数,也可由二维数组算出
                int lngCols = p_cols;	//arrStrGrid.GetLength(1);			//列数

                int lngRowIndex;		//当前行
                int lngColIndex;		//当前列

                //起止坐标
                int X1, X2, Y1, Y2;

                int lngLineLen;			//线长
                int lngLineHei;			//线高


                //计算坐标、线长、线高
                lngLineLen = rec.Width;
                lngLineHei = rec.Height;

                #region 包括横线就画
                if (p_gridLineFlag == GridLineFlag.Horizontal || p_gridLineFlag == GridLineFlag.Both)
                {
                    //******先画横线******
                    X1 = rec.X;
                    Y1 = rec.Y;
                    X2 = X1 + lngLineLen;

                    //最上边与最下边的线不画
                    for (lngRowIndex = 1; lngRowIndex < lngRows; lngRowIndex++)
                    {
                        Y1 += p_rowHeight;						//这里可以换成行高数组

                        //Y1 += p_arrRowsWidth[lngRowIndex - 1];//这里可以换成行高数组

                        Y2 = Y1;
                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                    }
                }
                #endregion

                #region 包括竖线就画
                if (p_gridLineFlag == GridLineFlag.Vertical || p_gridLineFlag == GridLineFlag.Both)
                {
                    //******再画竖线******
                    //列宽
                    int[] mArrColWidth = new int[lngCols];
                    mArrColWidth = p_arrColsWidth;

                    //Y不变
                    X1 = rec.X;
                    Y1 = rec.Y;
                    Y2 = Y1 + lngLineHei;

                    //最左边与右边的线不画
                    for (lngColIndex = 0; lngColIndex < lngCols - 1; lngColIndex++)
                    {
                        X1 += mArrColWidth[lngColIndex];
                        X2 = X1;
                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                    }
                }
                #endregion

            }//End If
            #endregion

            //******边框******
            if (p_gridBorderFlag != GridBorderFlag.None)
            {
                this.DrawGridBorder(g, rec, pmPen, p_gridBorderFlag);
            }

            //重置,不再变换
            this.ResetTransGrid();

        }
        #endregion

        #region protected void DrawGridLine(Graphics g,Rectangle p_rec,Pen pmPen,string[,] arrStrGrid,int p_rowHeight,int[] p_arrColsWidth,GridLineFlag p_gridLineFlag,GridBorderFlag p_gridBorderFlag,PointF p_scaleXY)
        /// <summary>
        /// 画网格线,标准备的横竖线交叉的线
        /// </summary>
        /// <param name="g">绘图表面</param>
        /// <param name="p_rec">绘图区</param>
        /// <param name="pmPen">绘图线的笔,可以定义颜色与线宽</param>
        /// <param name="arrStrGrid">二维数组,对应了网格行、列数</param>
        /// <param name="p_rowHeight">行高</param>
        /// <param name="p_arrColsWidth">列宽</param>
        /// <param name="p_gridLineFlag">网格线类型</param>
        /// <param name="p_gridBorderFlag">边框类型</param>
        /// <param name="p_scaleXY">水平与垂直方向缩放量</param>

        protected void DrawGridLine(Graphics g, Rectangle p_rec, Pen pmPen, string[,] arrStrGrid, int p_rowHeight, int[] p_arrColsWidth, GridLineFlag p_gridLineFlag, GridBorderFlag p_gridBorderFlag, PointF p_scaleXY)
        {
            int lngRows = arrStrGrid.GetLength(0);			//行数
            int lngCols = arrStrGrid.GetLength(1);			//列数
            DrawGridLine(g, p_rec, pmPen, lngRows, lngCols, p_rowHeight, p_arrColsWidth, p_gridLineFlag, p_gridBorderFlag, p_scaleXY);
        }
        #endregion

        #region 画合并线的核心 protected void DrawGridMergeLine(Graphics g,Rectangle p_rec,Pen pmPen,string[,] arrStrGrid,int p_rowHeight,int[] p_arrColsWidth,GridLineFlag p_gridLineFlag,GridBorderFlag p_gridBorderFlag,PointF p_scaleXY,GridMergeFlag gridMergeFlag)
        /// <summary>
        /// 画网格线,根据合并方式判断相邻单元格内容一格一格的画
        /// </summary>
        /// <param name="g">绘图表面</param>
        /// <param name="p_rec">绘图区</param>
        /// <param name="pmPen">绘图线的笔,可以定义颜色与线宽</param>
        /// <param name="arrStrGrid">二维数组</param>
        /// <param name="p_rowHeight">行高</param>
        /// <param name="p_arrColsWidth">列宽</param>
        /// <param name="p_gridLineFlag">网格线类型</param>
        /// <param name="p_gridBorderFlag">边框类型</param>
        /// <param name="p_scaleXY">水平与垂直方向缩放量</param>
        /// <param name="gridMergeFlag">网格单元格合并方式</param>        
        protected void DrawGridMergeLine(Graphics g, Rectangle p_rec, Pen pmPen, string[,] arrStrGrid, int p_rowHeight, int[] p_arrColsWidth, GridLineFlag p_gridLineFlag, GridBorderFlag p_gridBorderFlag, PointF p_scaleXY, GridMergeFlag gridMergeFlag)
        {
            //缩放矩阵,用于绘图
            Rectangle rec = new Rectangle(p_rec.X, p_rec.Y, p_rec.Width, p_rec.Height);

            int lngRows = arrStrGrid.GetLength(0);			//行数
            int lngCols = arrStrGrid.GetLength(1);			//列数

            //网格不合并直接画标准网格线,否则一个单元格一个单元格的画
            if (gridMergeFlag == GridMergeFlag.None)
            {
                this.DrawGridLine(g, rec, pmPen, lngRows, lngCols, p_rowHeight, p_arrColsWidth, p_gridLineFlag, p_gridBorderFlag, p_scaleXY);
                return;
            }
            else
            {
                #region 有网格线才画
                if (p_gridLineFlag != GridLineFlag.None)
                {
                    //变换
                    this.TransGrid(g, rec, p_scaleXY);

                    //起止坐标
                    int X1, X2, Y1, Y2;

                    //列宽
                    int[] mArrColWidth = new int[lngCols];
                    mArrColWidth = p_arrColsWidth;

                    #region	画单元格线

                    //边界不画
                    for (int i = 0; i < lngRows; i++)
                    {
                        X1 = rec.X;
                        Y1 = rec.Y;

                        for (int j = 0; j < lngCols; j++)
                        {
                            //-----水平线-----
                            X2 = X1 + mArrColWidth[j];

                            Y1 = rec.Y + p_rowHeight * i;		//****可用行高数组
                            Y2 = Y1;
                            //画第二行开始及以下的横线,当前行与上一行文本不同
                            if (i > 0)
                            {
                                //任意合并,只要相邻单元格内容不同就画线,即只要相邻单元格内容相同就合并
                                if (gridMergeFlag == GridMergeFlag.Any)
                                {
                                    //画线(条件:此列不合并 || 文本空 || 当前行与上一行文本不同)
                                    if (arrStrGrid[i, j] == "" || arrStrGrid[i, j] != arrStrGrid[i - 1, j])
                                    {
                                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                    }
                                }
                            }

                            //-----'竖线-----
                            //画第二列以后的竖线,当前列与上一列比较
                            if (j > 0)
                            {
                                Y2 = Y2 + p_rowHeight;			//****可用行高数组
                                X2 = X1;
                                //任意合并,只要相邻单元格内容不同就画线,即只要相邻单元格内容相同就合并
                                if (gridMergeFlag == GridMergeFlag.Any)
                                {
                                    //画线(条件:此行不合并 || 文本空 || 当前列与上一列文本不同)
                                    if (arrStrGrid[i, j] == "" || arrStrGrid[i, j] != arrStrGrid[i, j - 1])
                                    {
                                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                    }
                                }
                            }

                            //下一列,宽加上						
                            X1 += mArrColWidth[j];

                        }//End For 列	
                    }//End For 行					
                    #endregion

                    //******边框******
                    if (p_gridBorderFlag != GridBorderFlag.None)
                    {
                        this.DrawGridBorder(g, rec, pmPen, p_gridBorderFlag);
                    }

                    //重置,不再变换
                    this.ResetTransGrid();
                }//End If
                #endregion

            }//End If		
        }//End Function
        #endregion

        #region 标准不合并网格的文本 protected void DrawGridText(Graphics g,Rectangle p_rec,Brush pmBrush,string[,] arrStrGrid,int p_rowHeight,int[] p_arrColsWidth,string alignment,Font p_font,PointF p_scaleXY)
        /// <summary>
        /// 绘制网格文本,标准的行与列单元格,无合并
        /// </summary>
        /// <param name="g">绘图表面</param>
        /// <param name="p_rec">绘图区</param>
        /// <param name="pmBrush">绘图文本的画刷,可以定义颜色</param>
        /// <param name="arrStrGrid">二维字符数组(网格)</param>
        /// <param name="p_rowHeight">固定行高</param>
        /// <param name="p_arrColsWidth">列宽数组,为null时则平均列宽</param>
        /// <param name="alignment">由Left,Center,Right对齐方式第一个字母组成的串</param>
        /// <param name="p_scaleXY">指定X与Y向缩放比例值</param>  
        /// <param name="p_font"></param>
        protected void DrawGridText(Graphics g, Rectangle p_rec, Brush pmBrush, string[,] arrStrGrid, int p_rowHeight, int[] p_arrColsWidth, string alignment, Font p_font, PointF p_scaleXY)
        {
            try
            {
                //缩放矩阵,用于绘图
                Rectangle rec = new Rectangle(p_rec.X, p_rec.Y, p_rec.Width, p_rec.Height);

                Font font = p_font;
                if (font == null)
                {
                    font = new Font("宋体", 12.0F);
                }

                int lngRows = arrStrGrid.GetLength(0);			//行数
                int lngCols = arrStrGrid.GetLength(1);			//列数

                //列宽
                int[] mArrColWidth = new int[lngCols];
                mArrColWidth = p_arrColsWidth;

                //列对齐方式
                AlignFlag[] arrAlign;
                arrAlign = this.GetColsAlign(alignment);

                //变换
                this.TransGrid(g, rec, p_scaleXY);

                //起止坐标
                int X1, Y1, width;

                #region	画单元格文本

                StringFormat sf = new StringFormat();			//字符格式
                sf.LineAlignment = StringAlignment.Center;		//垂直居中
              //  sf.FormatFlags = StringFormatFlags.LineLimit | StringFormatFlags.NoWrap;
                sf.FormatFlags = StringFormatFlags.LineLimit;
                for (int i = 0; i < lngRows; i++)
                {
                    X1 = rec.X;
                    Y1 = rec.Y + p_rowHeight * i;					//****可用行数组

                    for (int j = 0; j < lngCols; j++)
                    {
                        width = mArrColWidth[j];

                        Rectangle recCell = new Rectangle(X1, Y1, width, p_rowHeight + 4);  //实际上居中会稍微偏上,因为字体有预留边距

                        sf.Alignment = StringAlignment.Near;				//默认左对齐						

                        if (arrAlign.Length > j)
                        {
                            if (arrAlign[j] == AlignFlag.Center)
                            {
                                sf.Alignment = StringAlignment.Center;		//居中
                            }
                            else if (arrAlign[j] == AlignFlag.Right)
                            {
                                sf.Alignment = StringAlignment.Far;		//居右
                            }
                        }
                        //改变字体,以Fonts属性的为准,若Fonts未被赋值,则按整个DarwGrid的字体来打印
                        Font realFont = font;
                        if (mFonts != null && mFonts.Length > j && mFonts[j] != null)
                        {
                            realFont = mFonts[j];
                        }

                        if (lngCols == 12)
                        {
                            if (j == 1 || j == 7)
                            {
                                if (arrStrGrid[i, j].Length > 10)
                                {
                                    g.DrawString(arrStrGrid[i, j], new Font("宋体", 10.0F, FontStyle.Bold), pmBrush, recCell, sf);
                                }
                                else
                                {
                                    g.DrawString(arrStrGrid[i, j], new Font("宋体", 10.0F, FontStyle.Bold), pmBrush, recCell, sf);
                                }
                            }
                            else
                            {
                                // g.DrawString(arrStrGrid[i, j], realFont, pmBrush, recCell, sf);
                                g.DrawString(arrStrGrid[i, j], new Font("宋体", 10.0F, FontStyle.Bold), pmBrush, recCell, sf);
                            }
                        }
                        else
                        {
                            if (j == 1 || j == 6)
                            {
                                if (arrStrGrid[i, j].Length > 10)
                                {
                                    g.DrawString(arrStrGrid[i, j], new Font("宋体", 10.0F, FontStyle.Bold), pmBrush, recCell, sf);
                                }
                                else
                                {
                                    g.DrawString(arrStrGrid[i, j], new Font("宋体", 10.0F, FontStyle.Bold), pmBrush, recCell, sf);
                                }
                            }
                            else
                            {
                                // g.DrawString(arrStrGrid[i, j], realFont, pmBrush, recCell, sf);
                                g.DrawString(arrStrGrid[i, j], new Font("宋体", 10.0F, FontStyle.Bold), pmBrush, recCell, sf);
                            }
                        }
                     
                       

                        X1 += width;

                    }//End For 列	

                }//End For 行					
                #endregion

                //重置,不再变换
                this.ResetTransGrid();

                //				font.Dispose();
            }
            catch (Exception e)
            {
                //MessageBox.Show(e.Message);
            }
            finally
            {

            }

        }//End Function
        #endregion

        #region 合并方式下的网格文本 protected void DrawGridText(Graphics g,Rectangle p_rec,Brush pmBrush,string[,] arrStrGrid,int p_rowHeight,int[] p_arrColsWidth,string alignment,Font p_font,PointF p_scaleXY,GridMergeFlag gridMergeFlag)
        /// <summary>
        /// 绘制网格文本,标准的行与列单元格,无合并
        /// </summary>
        /// <param name="g">绘图表面</param>
        /// <param name="p_rec">绘图区</param>
        /// <param name="pmBrush">绘图文本的画刷,可以定义颜色</param>
        /// <param name="arrStrGrid">二维字符数组(网格)</param>
        /// <param name="p_rowHeight">固定行高</param>
        /// <param name="p_arrColsWidth">列宽数组,为null时则平均列宽</param>
        /// <param name="alignment">由Left,Center,Right对齐方式第一个字母组成的串</param>
        /// <param name="p_scaleXY">指定X与Y向缩放比例值</param>        
        /// <param name="gridMergeFlag"></param>
        /// <param name="p_font"></param>
        protected void DrawGridMergeText(Graphics g, Rectangle p_rec, Brush pmBrush, string[,] arrStrGrid, int p_rowHeight, int[] p_arrColsWidth, string alignment, Font p_font, PointF p_scaleXY, GridMergeFlag gridMergeFlag)
        {
            if (gridMergeFlag == GridMergeFlag.None)
            {
                DrawGridText(g, p_rec, pmBrush, arrStrGrid, p_rowHeight, p_arrColsWidth, alignment, p_font, p_scaleXY);
                return;
            }

            try
            {
                //缩放矩阵,用于绘图
                Rectangle rec = new Rectangle(p_rec.X, p_rec.Y, p_rec.Width, p_rec.Height);

                Font font = p_font;
                if (font == null)
                {
                    font = new Font("宋体", 12.0F);
                }

                int lngRows = arrStrGrid.GetLength(0);			//行数
                int lngCols = arrStrGrid.GetLength(1);			//列数

                //列宽
                int[] mArrColWidth = new int[lngCols];
                mArrColWidth = p_arrColsWidth;

                //列对齐方式
                AlignFlag[] arrAlign;
                arrAlign = this.GetColsAlign(alignment);

                //变换
                this.TransGrid(g, rec, p_scaleXY);

                #region	画单元格文本

                StringFormat sf = new StringFormat();			//字符格式
                sf.LineAlignment = StringAlignment.Center;		//垂直居中
                sf.FormatFlags = StringFormatFlags.LineLimit | StringFormatFlags.NoWrap;

                CellRectangle cell = new CellRectangle(rec.X, rec.Y, 0, p_rowHeight);	//单元格

                for (int i = 0; i < lngRows; i++)
                {
                    for (int j = 0; j < lngCols; j++)
                    {
                        //.....
                        cell = this.GetMergeCell(new Point(rec.X, rec.Y), arrStrGrid, p_rowHeight, mArrColWidth, i, j);

                        Rectangle recCell = new Rectangle(cell.Left, cell.Top, cell.Width, cell.Height + 4);  //实际上居中会稍微偏上,因为字体有预留边距

                        sf.Alignment = StringAlignment.Near;				//默认左对齐						

                        if (arrAlign.Length > j)
                        {
                            if (arrAlign[j] == AlignFlag.Center)
                            {
                                sf.Alignment = StringAlignment.Center;		//居中
                            }
                            else if (arrAlign[j] == AlignFlag.Right)
                            {
                                sf.Alignment = StringAlignment.Far;		//居右
                            }
                        }

                        g.DrawString(arrStrGrid[i, j], font, pmBrush, recCell, sf);
                    }//End For 列	

                }//End For 行					
                #endregion

                //重置,不再变换
                this.ResetTransGrid();

                //font.Dispose();
            }
            catch (Exception e)
            {
                //MessageBox.Show(e.Message);
            }
            finally
            {

            }
        }//End Function
        #endregion

        #region protected void DrawGridBorder(Graphics g,Rectangle rec,Pen pmPen,GridBorderFlag p_gridBorderFlag)
        /// <summary>
        /// 绘制网格边框
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rec"></param>
        /// <param name="p_gridBorderFlag"></param>
        /// <param name="pmPen"></param>
        protected void DrawGridBorder(Graphics g, Rectangle rec, Pen pmPen, GridBorderFlag p_gridBorderFlag)
        {
            //无边框就退出
            if (p_gridBorderFlag == GridBorderFlag.None)
            {
                return;
            }

            float penwidth = 1F;		//笔宽
            int movXY = 0;				//根据笔的粗细要相应的调整矩形

            switch (p_gridBorderFlag)
            {
                case GridBorderFlag.Single:
                    break;
                case GridBorderFlag.SingleBold:
                    penwidth = 2F;
                    break;
                case GridBorderFlag.Double:
                    //双线内边框
                    g.DrawRectangle(pmPen, rec);
                    movXY = 2;
                    break;
                case GridBorderFlag.DoubleBold:
                    //双线内边框
                    g.DrawRectangle(pmPen, rec);
                    penwidth = 2F;
                    movXY = 3;
                    break;
            }


            Pen pen = (Pen)(pmPen.Clone());
            pen.Width = penwidth;

            //g.DrawRectangle(pen,rec);			

            Rectangle recBorder = rec;
            recBorder.X = rec.X - movXY;
            recBorder.Y = rec.Y - movXY;
            recBorder.Width = rec.Width + movXY * 2;
            recBorder.Height = rec.Height + movXY * 2;
            //外边框
            g.DrawRectangle(pen, recBorder);

            pen.Dispose();
        }

        #endregion

        /// <summary>
        /// 变换网格
        /// </summary>
        /// <param name="g"></param>
        /// <param name="p_rec"></param>
        /// <param name="p_scaleXY"></param>
        private void TransGrid(Graphics g, Rectangle p_rec, PointF p_scaleXY)
        {
            //坐标平移,使绘制的缩放图相对于原矩阵
            //float translateX = 0.0f;
            //float translateY = 0.0f;

            //缩放变换
            if (!p_scaleXY.IsEmpty)
            {
                g.ScaleTransform(p_scaleXY.X, p_scaleXY.Y);
            }
        }

        private void ResetTransGrid()
        {
            //this.Graphics.ResetTransform();
        }
        #endregion


        #region 画合并线的核心 protected void DrawGridLine(Graphics g,Rectangle p_rec,Pen pmPen,string[,] arrStrGrid,int p_rowHeight,int[] p_arrColsWidth,GridLineFlag p_gridLineFlag,GridBorderFlag p_gridBorderFlag,PointF p_scaleXY,GridMergeFlag gridMergeFlag)
        /// <summary>
        /// 画网格线,根据合并方式判断相邻单元格内容一格一格的画
        /// </summary>
        /// <param name="g">绘图表面</param>
        /// <param name="p_rec">绘图区</param>
        /// <param name="pmPen">绘图线的笔,可以定义颜色与线宽</param>
        /// <param name="arrStrGrid">二维数组</param>
        /// <param name="p_rowHeight">行高</param>
        /// <param name="p_arrColsWidth">列宽</param>
        /// <param name="p_gridLineFlag">网格线类型</param>
        /// <param name="p_gridBorderFlag">边框类型</param>
        /// <param name="p_scaleXY">水平与垂直方向缩放量</param>
        /// <param name="gridMergeFlag">网格单元格合并方式</param>

        protected void DrawGridLine(Graphics g, Rectangle p_rec, Pen pmPen, string[,] arrStrGrid, int p_rowHeight, int[] p_arrColsWidth, GridLineFlag p_gridLineFlag, GridBorderFlag p_gridBorderFlag, PointF p_scaleXY, GridMergeFlag gridMergeFlag)
        {
            //缩放矩阵,用于绘图
            Rectangle rec = new Rectangle(p_rec.X, p_rec.Y, p_rec.Width, p_rec.Height);

            int lngRows = arrStrGrid.GetLength(0);			//行数
            int lngCols = arrStrGrid.GetLength(1);			//列数

            //网格不合并直接画标准网格线,否则一个单元格一个单元格的画
            if (gridMergeFlag == GridMergeFlag.None)
            {
                this.DrawGridLine(g, rec, pmPen, lngRows, lngCols, p_rowHeight, p_arrColsWidth, p_gridLineFlag, p_gridBorderFlag, p_scaleXY);
                return;
            }
            else
            {
                #region 有网格线才画
                if (p_gridLineFlag != GridLineFlag.None)
                {
                    //变换
                    this.TransGrid(g, rec, p_scaleXY);

                    //起止坐标
                    int X1, X2, Y1, Y2;

                    //列宽
                    int[] mArrColWidth = new int[lngCols];
                    mArrColWidth = p_arrColsWidth;

                    #region	画单元格线

                    //边界不画
                    for (int i = 0; i < lngRows; i++)
                    {
                        X1 = rec.X;
                        Y1 = rec.Y;

                        for (int j = 0; j < lngCols; j++)
                        {
                            //-----水平线-----
                            X2 = X1 + mArrColWidth[j];

                            Y1 = rec.Y + p_rowHeight * i;		//****可用行高数组
                            Y2 = Y1;
                            //画第二行开始及以下的横线,当前行与上一行文本不同
                            if (i > 0)
                            {
                                switch (gridMergeFlag)
                                {
                                    case GridMergeFlag.None:
                                        //无合并,直接画线
                                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        break;
                                    case GridMergeFlag.Row:
                                        //仅行上相邻列相同就合并,即合并列
                                        //画线(条件:无条件,只要是行上进行列合并,水平线肯定画)
                                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        break;
                                    case GridMergeFlag.Col:
                                        //仅列上相邻行相同就合并,即合并列
                                        //画线(条件:此列不合并 || 文本空 || 当前行与上一行文本不同)
                                        if (arrStrGrid[i, j] == "" || arrStrGrid[i, j] != arrStrGrid[i - 1, j])
                                        {
                                            g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        }
                                        break;
                                    case GridMergeFlag.Any:
                                        //任意合并,只要相邻单元格内容不同就画线,即只要相邻单元格内容相同就合并
                                        //画线(条件: 文本空 || 当前行与上一行文本不同)
                                        if (arrStrGrid[i, j] == "" || arrStrGrid[i, j] != arrStrGrid[i - 1, j])
                                        {
                                            g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        }
                                        break;
                                }

                            }

                            //-----'竖线-----
                            //画第二列以后的竖线,当前列与上一列比较
                            if (j > 0)
                            {
                                Y2 = Y2 + p_rowHeight;			//****可用行高数组
                                X2 = X1;

                                switch (gridMergeFlag)
                                {
                                    case GridMergeFlag.None:
                                        //无合并,直接画线
                                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        break;
                                    case GridMergeFlag.Row:
                                        //仅行上相邻列相同就合并,即合并列
                                        //画线(条件:此行不合并 || 文本空 || 当前列与上一列文本不同)
                                        if (arrStrGrid[i, j] == "" || arrStrGrid[i, j] != arrStrGrid[i, j - 1])
                                        {
                                            g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        }
                                        break;
                                    case GridMergeFlag.Col:
                                        //仅列上相邻行相同就合并,即合并列
                                        //画线(条件:无,列竖线要画)
                                        g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        break;
                                    case GridMergeFlag.Any:
                                        //任意合并,只要相邻单元格内容不同就画线,即只要相邻单元格内容相同就合并
                                        //画线(条件: 文本空 || 当前行与上一行文本不同)
                                        if (arrStrGrid[i, j] == "" || arrStrGrid[i, j] != arrStrGrid[i, j - 1])
                                        {
                                            g.DrawLine(pmPen, X1, Y1, X2, Y2);
                                        }
                                        break;
                                }
                            }

                            //下一列,宽加上						
                            X1 += mArrColWidth[j];

                        }//End For 列	
                    }//End For 行					
                    #endregion

                    //******边框******
                    if (p_gridBorderFlag != GridBorderFlag.None)
                    {
                        this.DrawGridBorder(g, rec, pmPen, p_gridBorderFlag);
                    }

                    //重置,不再变换
                    this.ResetTransGrid();
                }//End If
                #endregion

            }//End If		
        }//End Function
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="g"></param>
        /// <param name="p_rec"></param>
        /// <param name="pmBrush"></param>
        /// <param name="arrStrGrid"></param>
        /// <param name="p_rowHeight"></param>
        /// <param name="p_arrColsWidth"></param>
        /// <param name="alignment"></param>
        /// <param name="p_font"></param>
        /// <param name="p_scaleXY"></param>
        /// <param name="gridMergeFlag"></param>
        protected void DrawGridText(Graphics g, Rectangle p_rec, Brush pmBrush, string[,] arrStrGrid, int p_rowHeight, int[] p_arrColsWidth, string alignment, Font p_font, PointF p_scaleXY, GridMergeFlag gridMergeFlag)
        {
            if (gridMergeFlag == GridMergeFlag.None)
            {
                DrawGridText(g, p_rec, pmBrush, arrStrGrid, p_rowHeight, p_arrColsWidth, alignment, p_font, p_scaleXY);
                return;
            }

            try
            {
                //缩放矩阵,用于绘图
                Rectangle rec = new Rectangle(p_rec.X, p_rec.Y, p_rec.Width, p_rec.Height);

                Font font = p_font;
                if (font == null)
                {
                    font = new Font("宋体", 12.0F);
                }

                int lngRows = arrStrGrid.GetLength(0);			//行数
                int lngCols = arrStrGrid.GetLength(1);			//列数

                //列宽
                int[] mArrColWidth = new int[lngCols];
                mArrColWidth = p_arrColsWidth;

                //列对齐方式
                AlignFlag[] arrAlign;
                arrAlign = this.GetColsAlign(alignment);

                //变换
                this.TransGrid(g, rec, p_scaleXY);

                #region	画单元格文本

                StringFormat sf = new StringFormat();			//字符格式
                sf.LineAlignment = StringAlignment.Center;		//垂直居中
                sf.FormatFlags = StringFormatFlags.LineLimit;	//| StringFormatFlags.NoWrap; //可换行否

                CellRectangle cell = new CellRectangle(rec.X, rec.Y, 0, p_rowHeight);	//单元格

                for (int i = 0; i < lngRows; i++)
                {
                    for (int j = 0; j < lngCols; j++)
                    {
                        //.....
                        cell = this.GetMergeCell(new Point(rec.X, rec.Y), arrStrGrid, p_rowHeight, mArrColWidth, i, j, gridMergeFlag);

                        Rectangle recCell = new Rectangle(cell.Left, cell.Top, cell.Width, cell.Height + 4);  //实际上居中会稍微偏上,因为字体有预留边距

                        sf.Alignment = StringAlignment.Near;				//默认左对齐						

                        if (arrAlign.Length > j)
                        {
                            if (arrAlign[j] == AlignFlag.Center)
                            {
                                sf.Alignment = StringAlignment.Center;		//居中
                            }
                            else if (arrAlign[j] == AlignFlag.Right)
                            {
                                sf.Alignment = StringAlignment.Far;		//居右
                            }
                        }

                        g.DrawString(arrStrGrid[i, j], font, pmBrush, recCell, sf);
                    }//End For 列	

                }//End For 行					
                #endregion

                //重置,不再变换
                this.ResetTransGrid();

                //font.Dispose();
            }
            catch (Exception e)
            {
               // MessageBox.Show(e.Message);
            }
            finally
            {

            }
        }//End Function


        #region protected virtual Cell GetMergeCell(Point GridLocation,string[,] arrStrGrid,int rowHeight,int[] ArrColWidth,int rowSel,int colSel,GridMergeFlag gridMergeFlag)

        /// <summary>
        /// 任意合并方式下返回指定单元格左顶宽高
        /// </summary>
        /// <param name="GridLocation">网格起点坐标</param>
        /// <param name="arrStrGrid">二维网格</param>
        /// <param name="rowHeight">行高</param>
        /// <param name="ArrColWidth">列宽数组</param>
        /// <param name="rowSel">指定单元格行</param>
        /// <param name="colSel">指定单元格列</param>
        /// <param name="gridMergeFlag"></param>
        /// <returns></returns>
        protected virtual CellRectangle GetMergeCell(Point GridLocation, string[,] arrStrGrid, int rowHeight, int[] ArrColWidth, int rowSel, int colSel, GridMergeFlag gridMergeFlag)
        {
            CellRectangle cell = new CellRectangle(0, 0, 0, 0);

            int lngRows = arrStrGrid.GetLength(0);	//行数
            int lngCols = arrStrGrid.GetLength(1);	//列数

            int lngMergeRows = 1;					//合并的行数(本身为1)
            int lngMergeCols = 1;					//合并的列数

            int lngStartRow = rowSel;				//记录与此单元格合并的起始行
            int lngEndRow = rowSel;					//以便计算高及起点Y坐标

            int lngStartCol = colSel;				//记录与此单元格合并的起始列
            int lngEndCol = colSel;					//以便计算宽及起点X坐标

            if (gridMergeFlag == GridMergeFlag.Any || gridMergeFlag == GridMergeFlag.Col || gridMergeFlag == GridMergeFlag.ColDependOnBeforeGroup)
            {
                //计算在"列"上进行行合并时起始行与合并的多少
                //往上查合并(列不变)
                for (int rowIndex = rowSel - 1; rowIndex >= 0; rowIndex--)
                {
                    if (arrStrGrid[rowSel, colSel] == arrStrGrid[rowIndex, colSel])
                    {
                        lngMergeRows++;
                        lngStartRow--;
                    }
                    else
                    {
                        break;
                    }
                }
                //往下查合并(列不变)
                for (int rowIndex = rowSel + 1; rowIndex < lngRows; rowIndex++)
                {
                    if (arrStrGrid[rowSel, colSel] == arrStrGrid[rowIndex, colSel])
                    {
                        lngMergeRows++;
                        lngEndRow++;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            if (gridMergeFlag == GridMergeFlag.Any || gridMergeFlag == GridMergeFlag.Row)
            {

                //计算在"行"上进行列合并时起始列与合并的多少
                //往左查合并(行不变)
                for (int colIndex = colSel - 1; colIndex >= 0; colIndex--)
                {
                    if (arrStrGrid[rowSel, colSel] == arrStrGrid[rowSel, colIndex])
                    {
                        lngMergeCols++;
                        lngStartCol--;
                    }
                    else
                    {
                        break;
                    }
                }
                //往右查合并(行不变)
                for (int colIndex = colSel + 1; colIndex < lngCols; colIndex++)
                {
                    if (arrStrGrid[rowSel, colSel] == arrStrGrid[rowSel, colIndex])
                    {
                        lngMergeCols++;
                        lngEndCol++;
                    }
                    else
                    {
                        break;
                    }
                }

            }

            //******************计算左顶宽高******************
            int cellLeft = GridLocation.X;
            int cellTop = GridLocation.Y + lngStartRow * rowHeight;	//若行高不是固定行高,可以计算之前行的行高总和

            int cellWidth = 0;
            int cellHeight = 0;

            //单元格合并列的前边的单元格列宽和
            for (int i = lngStartCol - 1; i >= 0; i--)
            {
                cellLeft += ArrColWidth[i];
            }

            //单元格合并列列宽和
            for (int i = lngStartCol; i <= lngEndCol; i++)
            {
                cellWidth += ArrColWidth[i];
            }

            cellHeight = lngMergeRows * rowHeight;					//若行高不是固定行高,可以计算所有行的行高总和

            cell = new CellRectangle(cellLeft, cellTop, cellWidth, cellHeight);

            return cell;
        }

        #endregion

    }
}

猜你喜欢

转载自blog.csdn.net/zx13525079024/article/details/84327802