DataGridView控件中数据表打印文档

C# DataGridView控件中数据表打印文档
一、打印类定义:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;

namespace WeightSystem
{
    class DataGridViewPrinter
    {
        //定义成员变量
        private DataGridView TheDataGridView;
        private PrintDocument ThePrintDocument;
        private bool IsCenterOnPage;
        private bool IsWithTitle;
        private string TheTitleText;
        private string TheTitleTextTwo;
        private Font TheTitleFont;
        private Font TheTitleFontTwo;
        private Color TheTitleColor;
        static int CurrentRow;
        static int PageNumber;
        static int PageNumberson;
        static int lastnumber;
        private int PageWidth;
        private int PageHeight;
        private int LeftMargin;
        private int TopMargin;
        private int RightMargin;
        private int BottomMargin;
        private float CurrentY;
        private float RowHeaderHeight;
        private List<float> RowsHeight;
        private List<float> ColumnsWidth;
        private float TheDataGridViewWidth;
        private List<int[]> mColumnPoints;
        private List<float> mColumnPointsWidth;
        private int mColumnPoint;
        //构造函数
        public DataGridViewPrinter(DataGridView aDataGridView, PrintDocument aPrintDocument,
            bool CenterOnPage, bool WithTitle, string aTitleText,
            string bTitleText, Font aTitleFont, Font bTitleFont,
            Color aTitleColor)
        {
            TheDataGridView = aDataGridView;
            ThePrintDocument = aPrintDocument;
            IsCenterOnPage = CenterOnPage;
            IsWithTitle = WithTitle;
            TheTitleText = aTitleText;
            TheTitleTextTwo = bTitleText;
            TheTitleFont = aTitleFont;
            TheTitleFontTwo = bTitleFont;
            TheTitleColor = aTitleColor;
            PageNumber = 0;
            PageNumberson = 0;
            RowsHeight = new List<float>();
            ColumnsWidth = new List<float>();
            mColumnPoints = new List<int[]>();
            mColumnPointsWidth = new List<float>();
            //利用ThePrintDocument.DefaultPageSettings.PaperSize获取页面的宽度和高度
            if (!ThePrintDocument.DefaultPageSettings.Landscape)
            {
                PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Width;
                PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Height;
            }
            else
            {
                PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Width;
                PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Height;
            }
            // 计算页边距
            LeftMargin = ThePrintDocument.DefaultPageSettings.Margins.Left;
            TopMargin = ThePrintDocument.DefaultPageSettings.Margins.Top;
            RightMargin = ThePrintDocument.DefaultPageSettings.Margins.Right;
            BottomMargin = ThePrintDocument.DefaultPageSettings.Margins.Bottom;
            CurrentRow = 0;
            lastnumber = 0;
        }
        //构造函数,初始化变量
        private float intergered(float num)
        {
            float num_interger;
            int point = 0;//小数点的位置
            string num_temp = num.ToString();
            for (int i = 0; i < num_temp.Length; i++)
            {
                if (num_temp[i] == '.')
                {
                    point = i;
                    break;
                }
            }
            if (point == 0)
                num_interger = num;
            else
                num_interger = Convert.ToSingle(num_temp.Substring(0, point + 1)) + 1;
            return num_interger;
        }
        //这个方法后面用到了。用于将小数宽度转换成整数宽度
        private void Calculate(Graphics g)
        {
            //和分页有关,只有在绘制第一页的时候计算这些数据
            //后续页不再重复计算
            if (PageNumber == 0)
            {
                //获取dataGridView的一些参数,行高、列宽、表格的宽度等
                //根据这些参数来绘制打印内容
                //因为dataGridView中的内容就是要用来打印的内容
                //是需要在PrintDocument的PrintPage事件中绘制的
                //局部变量定义
                float totalwidth = PageWidth - (float)LeftMargin - RightMargin;//总宽度
                int cols = 0;//记录列数
                float minwidth;//最小宽度
                //记录可见列数,用于计算列的平均宽度
                for (int ic = 0; ic < TheDataGridView.Columns.Count; ic++)//calculate the numbers of columns
                {
                    if (TheDataGridView.Columns[ic].Visible)
                        cols++;
                }
                //表示列平均宽度的局部变量,后面有用到,用来初始化tmpWidth
                minwidth = totalwidth / cols;
                //局部变量,临时保存中间结果
                //最终结果会保存到成员变量(字段)里
                //存储浮点数,通常的宽度和高度的矩形的有序对
                SizeF tmpSize = new SizeF();//表示矩形?
                Font tmpFont;               //字体    
                float tmpWidth = minwidth;   //列宽
                //表示dataGridView宽度的字段
                TheDataGridViewWidth = 0;
                //两层for循环。外层逐列,内层逐行。
                //获取绘制列标题的参数
                for (int i = 0; i < TheDataGridView.Columns.Count; i++)
                {
                    //决定字体?是的,决定列标题的字体
                    tmpFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font;
                    if (tmpFont == null)
                        tmpFont = TheDataGridView.DefaultCellStyle.Font;
                    if (tmpFont.Size < 13)
                        tmpFont = new Font(tmpFont.Name.ToString(), 13, FontStyle.Regular, GraphicsUnit.Point);
                    //干什么?测量用指定Font绘制的指定字符串
                    tmpSize = g.MeasureString(TheDataGridView.Columns[i].HeaderText, tmpFont);
                    //获取表头高度,后面有用到
                    //将高度设置为含有的字符个数
                    RowHeaderHeight = tmpSize.Height;
                    //设置逐行绘制的参数
                    for (int j = 0; j < TheDataGridView.Rows.Count; j++)
                    {
                        //确定字体,单元中使用的字体
                        tmpFont = TheDataGridView.Rows[j].DefaultCellStyle.Font;
                        if (tmpFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
                            tmpFont = TheDataGridView.DefaultCellStyle.Font;
                        if (tmpFont.Size < 12)
                        {
                            tmpFont = new Font(tmpFont.Name.ToString(), 12, FontStyle.Regular, GraphicsUnit.Point);
                        }

                        //这个结构体是用来干什么的?获取dataGridView的宽度和高度?
                        //测量当前列的每一行的单元格
                        tmpSize = g.MeasureString("Anything", tmpFont);
                        tmpSize = g.MeasureString(TheDataGridView.Rows[j].Cells[i].EditedFormattedValue.ToString(), tmpFont);

                        //字段行高,后面有用到

                        RowsHeight.Add(tmpSize.Height);
                    }
                    //局部变量tmpWidth最终用来确定成员变量TheDataGridViewWidth
                    //遍历每一列的时候累加每一列的列宽,进而得到表格的宽度
                    //这样不会使计算得到的表格宽度大于表格实际宽度么?
                    if (TheDataGridView.Columns[i].Visible)
                    {
                        TheDataGridViewWidth += tmpWidth;
                    }
                    //当前列中最宽的单元格的宽度
                    tmpWidth = intergered(tmpWidth);
                    ColumnsWidth.Add(tmpWidth);
                }
                //循环变量
                int k;
                int mStartPoint = 0;
                //for循环,正向遍历确定第一个可见的列的序号
                for (k = 0; k < TheDataGridView.Columns.Count; k++)
                    if (TheDataGridView.Columns[k].Visible)
                    {
                        mStartPoint = k;
                        break;
                    }
                int mEndPoint = TheDataGridView.Columns.Count;
                //for循环,逆向遍历确定最后一个可见的列的序号
                for (k = TheDataGridView.Columns.Count - 1; k >= 0; k--)
                    if (TheDataGridView.Columns[k].Visible)
                    {
                        mEndPoint = k + 1;
                        break;
                    }
                //宽度、打印区域
                float mTempWidth = TheDataGridViewWidth;
                mColumnPoints.Add(new int[] { mStartPoint, mEndPoint });
                mColumnPointsWidth.Add(mTempWidth);
                mColumnPoint = 0;
            }
        }
        //到目前为止还什么都没有绘制呢?但是几乎设置了与绘制所有表格内容相关的参数
        //当DataGridView中列数过多时,单元格内的内容可能显示不全,尝试了一些方法
        //比如更改页面大小,增加高度让文本竖向排列(竖向绘制文本比较麻烦),但是都没有成功。
        // The funtion that print the title, page number, and the header row
        private void DrawHeader(Graphics g)
        {
            //当前纵坐标
            CurrentY = (float)TopMargin;
            #region  分页时绘制页号和打印日期
            // Printing the page number (if isWithPaging is set to true)
            //分页处理
            if (lastnumber == mColumnPoint)//一页表未打印完全
            {
                PageNumber++;
            }
            else
            {
                PageNumber = 1;
                lastnumber = mColumnPoint;
            }
            //绘制页号
            PageNumberson = mColumnPoint + 1;
            string PageString = "页号: " + PageNumber.ToString();
            //string PageString = "页号: " + PageNumber.ToString() + "-" + PageNumberson.ToString();
            StringFormat PageStringFormat = new StringFormat();
            PageStringFormat.Trimming = StringTrimming.Word;
            PageStringFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
            PageStringFormat.Alignment = StringAlignment.Far;
            Font PageStringFont = new Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point);
            RectangleF PageStringRectangle = new RectangleF((float)LeftMargin - 50, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(PageString, PageStringFont).Height);
            g.DrawString(PageString, PageStringFont, new SolidBrush(Color.Black), PageStringRectangle, PageStringFormat);
            //绘制打印日期
            string printtime = "打印日期: " + DateTime.Now.Year.ToString() + "."
                + DateTime.Now.Month.ToString() + "." + DateTime.Now.Day.ToString();
            StringFormat PrintTimeFormat = new StringFormat();
            PrintTimeFormat.Trimming = StringTrimming.Word;
            PrintTimeFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
            PrintTimeFormat.Alignment = StringAlignment.Near;
            g.DrawString(printtime, PageStringFont, new SolidBrush(Color.Black), PageStringRectangle, PrintTimeFormat);
            CurrentY += g.MeasureString(PageString, PageStringFont).Height;
            //分页处理结束
            #endregion
            #region  有标题的时候才会用到
            // Printing the title (if IsWithTitle is set to true)
            //绘制标题
            if (IsWithTitle)
            {
                StringFormat TitleFormat = new StringFormat();
                TitleFormat.Trimming = StringTrimming.Word;
                TitleFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
                if (IsCenterOnPage)
                    TitleFormat.Alignment = StringAlignment.Center;
                else
                    TitleFormat.Alignment = StringAlignment.Near;
                if (TheTitleFont.Size < 13)
                {
                    TheTitleFont = new Font(TheTitleFont.Name.ToString(), 13, FontStyle.Bold, GraphicsUnit.Point);
                }
                RectangleF TitleRectangle = new RectangleF((float)LeftMargin, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(TheTitleText, TheTitleFont).Height);
                g.DrawString(TheTitleText, TheTitleFont, new SolidBrush(TheTitleColor), TitleRectangle, TitleFormat);
                CurrentY += g.MeasureString(TheTitleText, TheTitleFont).Height;
                RectangleF TitleRectangleTwo = new RectangleF((float)LeftMargin, CurrentY, (float)PageWidth - (float)RightMargin - (float)LeftMargin, g.MeasureString(TheTitleTextTwo, TheTitleFontTwo).Height);
                g.DrawString(TheTitleTextTwo, TheTitleFontTwo, new SolidBrush(TheTitleColor), TitleRectangleTwo, TitleFormat);
                CurrentY += g.MeasureString(TheTitleTextTwo, TheTitleFontTwo).Height;
            }
            //绘制标题结束
            #endregion
            // Calculating the starting x coordinate that the printing process will start from
            //当前横坐标
            float CurrentX = (float)LeftMargin;
            if (IsCenterOnPage)
                CurrentX += (((float)PageWidth - (float)RightMargin - (float)LeftMargin) - mColumnPointsWidth[mColumnPoint]) / 2.0F;
            // Setting the HeaderFore style
            Color HeaderForeColor = TheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor;
            if (HeaderForeColor.IsEmpty)
                HeaderForeColor = TheDataGridView.DefaultCellStyle.ForeColor;
            //实例化一个画笔
            SolidBrush HeaderForeBrush = new SolidBrush(HeaderForeColor);
            // Setting the HeaderBack style
            Color HeaderBackColor = TheDataGridView.ColumnHeadersDefaultCellStyle.BackColor;
            if (HeaderBackColor.IsEmpty)
                HeaderBackColor = TheDataGridView.DefaultCellStyle.BackColor;
            SolidBrush HeaderBackBrush = new SolidBrush(HeaderBackColor);
            // Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
            Pen TheLinePen = new Pen(TheDataGridView.GridColor, 1);
            // Setting the HeaderFont style
            Font HeaderFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font;
            if (HeaderFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style
                HeaderFont = TheDataGridView.DefaultCellStyle.Font;
            if (HeaderFont.Size < 13)
            {
                HeaderFont = new Font(HeaderFont.Name.ToString(), 13, FontStyle.Bold, GraphicsUnit.Point);
            }
            // Calculating and drawing the HeaderBounds       
            RectangleF HeaderBounds = new RectangleF(CurrentX, CurrentY,
                mColumnPointsWidth[mColumnPoint], RowHeaderHeight);
            g.FillRectangle(HeaderBackBrush, HeaderBounds);//用矩形来绘制单元格
            // Setting the format that will be used to print each cell of the header row
            StringFormat CellFormat = new StringFormat();
            CellFormat.Trimming = StringTrimming.Word;
            CellFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
            // Printing each visible cell of the header row
            //表示单元格的矩形
            RectangleF CellBounds;
            float ColumnWidth;
            for (int i = (int)mColumnPoints[mColumnPoint].GetValue(0); i < (int)mColumnPoints[mColumnPoint].GetValue(1); i++)
            {
                if (!TheDataGridView.Columns[i].Visible) continue; // If the column is not visible then ignore this iteration
                ColumnWidth = ColumnsWidth[i];
                CellFormat.Alignment = StringAlignment.Center;
                CellBounds = new RectangleF(CurrentX, CurrentY, ColumnWidth, RowHeaderHeight);
                // Printing the cell text
                g.DrawString(TheDataGridView.Columns[i].HeaderText, HeaderFont, HeaderForeBrush, CellBounds, CellFormat);
                // Drawing the cell bounds
                if (TheDataGridView.RowHeadersBorderStyle != DataGridViewHeaderBorderStyle.None) // Draw the cell border only if the HeaderBorderStyle is not None
                    g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowHeaderHeight);
                CurrentX += ColumnWidth;
            }
            CurrentY += RowHeaderHeight;
        }
        //绘制表格标题以及列标题,可能有问题,因为运行的时候一些条件下无法完全显示所有列
        //动态绘制行数、列数!
        //动态绘制行高、列宽?
        private bool DrawRows(Graphics g)
        {
            // Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
            Pen TheLinePen = new Pen(TheDataGridView.GridColor, 1);
            // The style paramters that will be used to print each cell
            Font RowFont;
            Color RowForeColor;
            Color RowBackColor;
            //三支画笔?
            SolidBrush RowForeBrush;
            SolidBrush RowBackBrush;
            SolidBrush RowAlternatingBackBrush;
            // Setting the format that will be used to print each cell
            StringFormat CellFormat = new StringFormat();
            CellFormat.Trimming = StringTrimming.Word;
            CellFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit;
            //表示矩形相关参数的结构
            RectangleF RowBounds;
            float CurrentX;
            float ColumnWidth;

            //逐行绘制,绘制所有可见的单元格
            while (CurrentRow < TheDataGridView.Rows.Count - 1)
            {
                if (TheDataGridView.Rows[CurrentRow].Visible)
                {
                    // Setting the row font style
                    //确定字体
                    RowFont = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.Font;
                    if (RowFont == null)
                        RowFont = TheDataGridView.DefaultCellStyle.Font;
                    if (RowFont.Size < 12)
                    {
                        RowFont = new Font(RowFont.Name.ToString(), 12, FontStyle.Regular, GraphicsUnit.Point);
                    }
                    // 设置行单元格的前景风格
                    RowForeColor = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.ForeColor;
                    if (RowForeColor.IsEmpty)
                        RowForeColor = TheDataGridView.DefaultCellStyle.ForeColor;
                    RowForeBrush = new SolidBrush(RowForeColor);
                    //设置行单元格背景风格 
                    RowBackColor = TheDataGridView.Rows[CurrentRow].DefaultCellStyle.BackColor;
                    if (RowBackColor.IsEmpty)
                    {
                        RowBackBrush = new SolidBrush(TheDataGridView.DefaultCellStyle.BackColor);
                        RowAlternatingBackBrush = new SolidBrush(TheDataGridView.AlternatingRowsDefaultCellStyle.BackColor);
                    }
                    else
                    {
                        RowBackBrush = new SolidBrush(RowBackColor);
                        RowAlternatingBackBrush = new SolidBrush(RowBackColor);
                    }
                    // 根据左页边距确定绘制起始点的横坐标
                    CurrentX = (float)LeftMargin;
                    if (IsCenterOnPage)
                        CurrentX += (((float)PageWidth - (float)RightMargin - (float)LeftMargin) - mColumnPointsWidth[mColumnPoint]) / 2.0F;
                    // 计算行边界            
                    RowBounds = new RectangleF(CurrentX, CurrentY, mColumnPointsWidth[mColumnPoint], RowsHeight[CurrentRow]);
                    //填充行背景
                    if (CurrentRow % 2 == 0)
                        g.FillRectangle(RowBackBrush, RowBounds);
                    else
                        g.FillRectangle(RowAlternatingBackBrush, RowBounds);
                    // 绘制当前行的所有可见的单元格,这个没有问题               
                    for (int CurrentCell = (int)mColumnPoints[mColumnPoint].GetValue(0); CurrentCell < (int)mColumnPoints[mColumnPoint].GetValue(1); CurrentCell++)
                    {
                        if (!TheDataGridView.Columns[CurrentCell].Visible) continue;
                        #region 设置文本交错排列(不用)
                        //if (TheDataGridView.Columns[CurrentCell].ValueType.ToString() == "System.Single"
                        //    || TheDataGridView.Columns[CurrentCell].ValueType.ToString() == "System.Double")
                        //    CellFormat.Alignment = StringAlignment.Far;
                        //else
                        //    CellFormat.Alignment = StringAlignment.Near;
                        #endregion 
                        CellFormat.Alignment = StringAlignment.Center; //设置文本在中间
                        ColumnWidth = ColumnsWidth[CurrentCell];
                        RectangleF CellBounds = new RectangleF(CurrentX, CurrentY, ColumnWidth, RowsHeight[CurrentRow]);
                        // 绘制单元格中的文本
                        g.DrawString(TheDataGridView.Rows[CurrentRow].Cells[CurrentCell].EditedFormattedValue.ToString(), RowFont, RowForeBrush, CellBounds, CellFormat);
                        // 绘制单元格边界
                        if (TheDataGridView.CellBorderStyle != DataGridViewCellBorderStyle.None)
                            g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowsHeight[CurrentRow]);
                        CurrentX += ColumnWidth;
                    }
                    CurrentY += RowsHeight[CurrentRow];
                    // 每绘制完一行,判断是否到达页边界
                    // 如果到达边界,就开始另一页的绘制
                    //return true此函数就退出了
                    if ((int)CurrentY > (PageHeight - TopMargin - BottomMargin))
                    {
                        CurrentRow++;
                        return true;
                    }
                }
                CurrentRow++;
            }
            CurrentRow = 0;//why excute the word and then jump to DrawHeader()
            mColumnPoint++; // Continue to print the next group of columns
            //绘制完所有行的时候,才执行下面的代码
            //才会返回bool值
            //这是在一页内或当前页内绘制了dataGridView中的所有行
            if (mColumnPoint == mColumnPoints.Count) // Which means all columns are printed
            {
                mColumnPoint = 0;
                return false;
            }
            else
                return true;
        }
        //绘制行的方法
        //当dataGridView中行特别多时不能在一页内全显示,但是也没有自动分页
        //指定分页后,也只是绘制相关信息,但是并没有真的分页
        //而对分页的处理,主要是相关信息的绘制只出现在DrawHeader中
        //不过,分页处理应该是在绘制行的时候根据实际情况进行的啊

        public bool DrawDataGridView(Graphics g)
        {
            bool hasMorePages;
            try
            {
                //是其他方法的基础,若是删除,只能绘制标题
                Calculate(g);
                //绘制列标题,有问题,一些情况下不能绘制出DataGridView中的所有的列
                //也可能是Calculate()方法中有问题
                DrawHeader(g);
                //绘制所有行
                hasMorePages = DrawRows(g);
                return hasMorePages;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Operation failed: " + ex.Message.ToString(), Application.ProductName + " - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }
        //调用其他方法,其他方法没问题,此方法就不会有什么问题
        //为什么返回值为bool型呢?为真会怎样?为假又会怎样?怎么实现分页绘制?
        //是void也可以,但是不能分页
    }
}

二、应用:
1、定义类
DataGridViewPrinter printer1;
2、窗体中添加控件
要添加的控件

控件设置

3、打印事件
//打印按钮
private void btnPrint_Click(object sender, EventArgs e)
{
printer1 = new DataGridViewPrinter(dgvTable, printDocument1, true, true,
“”, “温湿度历史信息”, new Font(“宋体”, 15, FontStyle.Regular),
new Font(“宋体”, 15, FontStyle.Regular), Color.Black);
//printDialog1.Document = printDocument1;//获取PrintDocument对象,属性直接设置
//打开打印设置对话框并传递返回值
if (printDialog1.ShowDialog() == DialogResult.OK)
{
if (MessageBox.Show(“是否要预览打印文档”, “打印预览”, System.Windows.Forms.MessageBoxButtons.YesNo) == DialogResult.Yes)
{
this.printPreviewDialog1.UseAntiAlias = true;
this.printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
else
{
this.printDocument1.Print();//不预览,直接打印
}
}
}
//打印事件
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
//e.HasMorePage为真,系统会自动调用printDocument1_PrintPage方法。实现在预览时的分页
if (printer1.DrawDataGridView(e.Graphics))
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false;
}
}

猜你喜欢

转载自blog.csdn.net/qq_30725967/article/details/85249920
今日推荐