winfrom 打印表格 字符串的封装实现代码 附源码下载_C#教程

所以对于应用层用着还不是很方便。最近做一个项目顺便就封装了一个调用默认打印机的类。虽说有几个小bug,但对于目前来说,已经满足需求了。以后不够了在来升级吧。

1,关于打印上下左右边距和纸张的高宽。以往都把这些写死到代码里面。既然是调用默认打印机,打印机的型号自然有差异。所以我就把这些配置放到app.config里面。但又怕每次打印都加载config影响效率。故此设计了个PrintPaper类。里面所有属性都是静态的。还有一个静态的构造方法。这样只有在程序开始运行加载一次config。之后就直接从内存读取了。

PrintPaper类

复制代码 代码如下:

/*CreateBy:Bonker,Date:20121115*/
     /// <summary>
     /// 从配置文件读取纸张的大小,与边框的距离
     /// </summary>
     public class PrintPaper
     {
         /// <summary>
         /// 距离上边界的距离
         /// </summary>
         public static int MarginTop { set; get; }
         /// <summary>
         /// 距离左边界的距离
         /// </summary>
         public static int MarginLeft { set; get; }
         /// <summary>
         /// 距离右边界的距离
         /// </summary>
         public static int MarginRight { set; get; }
         /// <summary>
         /// 距离下边界的距离
         /// </summary>
         public static int MarginBottom { set; get; }
         /// <summary>
         /// 纸张的宽度
         /// </summary>
         public static int Width { set; get; }
         /// <summary>
         /// 纸张的高度
         /// </summary>
         public static int Height { set; get; }
         /// <summary>
         /// 异常情况
         /// </summary>
         public static string Error { set; get; }

         //对于静态属性和构造方法。当第一次使用该类的时候,先初始化静态属性,然后调用静态类。
         //故此配置文件只加载一次,以后调用都会从内存中读取。
         //此中写法的好处,一次加载,以后不再加载,速度快。弊端:程序运行过程中,改变了config配置。则需重新运行程序。配置才加载生效。
         static PrintPaper()
         {
             //先给异常赋空值,当异常不为空时。说明配置数据有问题,或者程序有异常
             Error = null;
             string marginTop = BonkerConfig.GetConfig("marginTop");
             string marginBottom = BonkerConfig.GetConfig("marginBottom");
             string marginLeft = BonkerConfig.GetConfig("marginLeft");
             string marginRight = BonkerConfig.GetConfig("marginRight");
             //margin的值可以为负值,但是width只能为正,
             //marginTop,等值默认已经为0,如果margin不为空,取值复制给margin
             try
             {
                 if (!string.IsNullOrWhiteSpace(marginTop))
                 {
                     MarginTop = int.Parse(marginTop);
                 }
                 if (!string.IsNullOrWhiteSpace(marginTop))
                 {
                     MarginBottom = int.Parse(marginBottom);
                 }
                 if (!string.IsNullOrWhiteSpace(marginTop))
                 {
                     MarginLeft = int.Parse(marginLeft);
                 }
                 if (!string.IsNullOrWhiteSpace(marginTop))
                 {
                     MarginRight = int.Parse(marginRight);
                 }
             }
             catch (Exception ex)
             {
                 //如果有异常继续
                 Error = ex.Message;
                 return;
             }
             //判断纸张宽度
             try
             {
                 //如果paperWidth配置不为正,则为PrintCore类打印的时候,则去默认值
                 string width = BonkerConfig.GetConfig("paperWidth");
                 string height = BonkerConfig.GetConfig("paperWidth");
                 if (!string.IsNullOrWhiteSpace(width))
                 {
                     Width = int.Parse(width);
                 }
                 if (!string.IsNullOrWhiteSpace(height))
                 {
                     Height = int.Parse(width);
                 }
             }
             catch (Exception ex)
             {
                 //如果有异常继续
                 Error = ex.Message;
                 return;
             }
         }
     }

app.config的内容

复制代码 代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <appSettings>
    <!--******************************连接字符串设置************************************-->
    <add key="DBConnectionStr" value=" "/>
    <!--********************************打印边界设置**********************************-->
    <!--打印纸的距四个边界的距离,为空这表示默认为0,可以为负值-->
    <!--与上边界距离-->
    <add key="marginTop" value=""/>
    <!--与上边界距离-->
    <add key="marginBottom" value=""/>
    <!--与上边界距离-->
    <add key="marginLeft" value=""/>
    <!--与上边界距离-->
    <add key="marginRight" value=""/>
    <!--********************************打印纸大小设置**********************************-->
    <!--打印纸张的大小,为空表示取默认值,不可以为负值 -->
    <!--纸张的宽度-->
    <add key="paperWidth" value=""/>
    <!--纸张的高度-->
    <add key="paperHeight" value=""/>
    <!--*******************************************************************************-->
  </appSettings>
</configuration>

2,打印表格,翻阅了很多msdn大神的代码。大致有点眉目。打印表格是在一点打印完字体后,然后不改变X,Y坐标继续打印个矩形。所以就有表格了。这样的表格理论上表格的四个边框有点细。里面的小格子有点粗。但打印出来后基本就没差别了。

    打印表格是自适应表格里面的文字最大的宽度。但如果表格里面确实列很少,没列的最大宽度又很小。打印完真整个表格没有页面的纸张宽。那会自动拉宽每一列的宽度。

打印的核心类PrintCore

复制代码 代码如下:

/*CreateBy:Bonker,Date:20121115*/
    /// <summary>
    /// 打印类,负责打印表格,普通行等。
    /// </summary>
    public class PrintCore
    {
        /// <summary>
        /// 打印基础封装类PrintDocument
        /// </summary>
        public PrintDocument printDoc { set; get; }
        /// <summary>
        /// 当前打印的x坐标
        /// </summary>
        public float currentX { set; get; }
        /// <summary>
        /// 当前打印的Y坐标
        /// </summary>
        public float currentY { set; get; }
        /// <summary>
        /// 默认打印字体
        /// </summary>
        public Font defaultFont { set; get; }
        /// <summary>
        /// 打印的画刷,默认黑色加粗
        /// </summary>
        public Brush defaultBrush { set; get; }
        /// <summary>
        /// 是否居中打印,默认为false
        /// </summary>
        public bool isCenter { set; get; }
        /// <summary>
        /// 异常错误
        /// </summary>
        public string Error { set; get; }

        private Graphics graphic { set; get; }
        /// 构造函数
        /// </summary>
        /// <param name="_printDoc">打印基础类</param>
        /// <param name="_currentX">打印开始的x坐标,默认为0</param>
        /// <param name="_currentY">打印开始的y坐标,默认为0</param>
        public PrintCore(PrintDocument _printDoc, Graphics _graphics, Font _defaultFont, float _currentX = 0, float _currentY = 0)
        {
            this.printDoc = _printDoc;
            this.currentX = _currentX;
            this.currentY = _currentY;
            this.defaultFont = _defaultFont;
            this.graphic = _graphics;
            this.defaultBrush = new SolidBrush(Color.Black); //默认加粗黑色
            this.isCenter = false;
            //读取配置文件
            printDocConfig(_printDoc);
            Error = PrintPaper.Error;
        }
        private void printDocConfig(PrintDocument _printDoc)
        {
            _printDoc.DefaultPageSettings.Margins = new Margins(PrintPaper.MarginLeft, PrintPaper.MarginRight, PrintPaper.MarginTop, PrintPaper.MarginBottom);
            //当paper配置的宽度和高度都大于0时,才配置。否则忽略
            if (PrintPaper.Width > 0 && PrintPaper.Height > 0)
            {
                _printDoc.DefaultPageSettings.PaperSize = new PaperSize("", PrintPaper.Width, PrintPaper.Height);
            }

        }
        /// <summary>
        /// 打印字符串,系统可以总动判断换行打印。
        /// </summary>
        /// <param name="prnStr">打印的字符串</param>
        /// <param name="isPrintLine">打印完成后,是否换行,默认为true</param>
        public void printString(string prnStr, bool isPrintLine = true)
        {
            //打印字符串,根据字符串长度,和纸张宽度,高度等自动换行
            SizeF measure = graphic.MeasureString(prnStr, defaultFont);
            //如果x坐标不为0,或者打印的一行宽度大于纸张的宽度,则居中打印是没用的。不考虑打印
            if (!isCenter || currentX != 0 || printDoc.DefaultPageSettings.PaperSize.Width < measure.Width)
            {
                //计算打印这么多字要多少行
                int rows = (int)Math.Ceiling(measure.Width / (printDoc.DefaultPageSettings.PaperSize.Width - currentX));
                //根据行,算出要打印的边界矩形框
                graphic.DrawString(prnStr, defaultFont, defaultBrush, new Rectangle((int)currentX, (int)currentY, (int)Math.Ceiling((printDoc.DefaultPageSettings.PaperSize.Width - currentX)), (int)Math.Ceiling((measure.Height * rows))));
                if (isPrintLine)//如果换行
                {
                    currentY = currentY + measure.Height * rows;
                    currentX = 0;
                }
                else
                {
                    currentY = currentY + measure.Height * (rows - 1);
                    currentX = (measure.Width % (printDoc.DefaultPageSettings.PaperSize.Width - currentX)) + currentX;
                }
            }
            else
            {
                //居中打印一行
                //计算打印前的留白宽度
                float blank = (printDoc.DefaultPageSettings.PaperSize.Width - measure.Width) / 2.0f;
                currentX = currentX + blank;
                graphic.DrawString(prnStr, defaultFont, defaultBrush, currentX, currentY);
                if (isPrintLine)//如果换行
                {
                    currentX = 0;
                    currentY = currentY + measure.Height;
                }
                else
                {
                    currentX = currentX + measure.Width;
                }
            }
        }
        /// <summary>
        /// 打印表格,自适应没列的宽度
        /// </summary>
        /// <param name="prnDgv"></param>
        /// <param name="isPrintLine"></param>
        public void printDataGridView(DataGridView prnDgv, Font titleFont, Brush titleBrush, Color titleBackGroup, bool isPrintLine = true)
        {
            if (prnDgv == null)
            {
                return;
            }
            prnDgv.AllowUserToAddRows = false;
            //记录每一列的宽度
            int[] columnWidths = new int[prnDgv.ColumnCount];
            //******************取每列的最大宽度***********************
            //先计算表头的宽度
            for (int i = 0; i < prnDgv.ColumnCount; i++)
            {
                string celValue = prnDgv.Columns[i].HeaderText;
                SizeF measure = graphic.MeasureString(celValue, titleFont);
                columnWidths[i] = (int)Math.Ceiling(measure.Width);//把打印表头所占的宽度 先放到columnWidths里面
            }
            //计算表中数据打印的最大宽度
            for (int i = 0; i < prnDgv.Rows.Count; i++)
            {
                for (int j = 0; j < prnDgv.ColumnCount; j++)
                {
                    string celValue = prnDgv[j, i].Value.ToString();
                    SizeF measure = graphic.MeasureString(celValue, defaultFont);
                    if (columnWidths[j] < measure.Width)//如果宽度小于打印宽度,则把长的打印宽度赋值给列宽
                    {
                        columnWidths[j] = (int)Math.Ceiling(measure.Width);
                    }
                }
            }

            //如果表格的宽度小于纸张的宽度,表格没列的宽度加大
            int allColumsWidth = 0;
            for (int i = 0; i < prnDgv.ColumnCount; i++)
            {
                allColumsWidth += columnWidths[i];//把打印表头所占的宽度 先放到columnWidths里面
            }
            if (allColumsWidth + prnDgv.ColumnCount < PrintPaper.Width)
            {
                int columnAddWidth = (PrintPaper.Width - allColumsWidth - prnDgv.ColumnCount) / prnDgv.ColumnCount;
                for (int i = 0; i < prnDgv.ColumnCount; i++)
                {
                    columnWidths[i] += columnAddWidth;
                }
            }
            //*************************************************************

            currentX = 0;
            int titleHeight = (int)Math.Ceiling(graphic.MeasureString("1e{(汗", titleFont).Height);
            //打印表头
            for (int i = 0; i < prnDgv.ColumnCount; i++)
            {
                string celValue = prnDgv.Columns[i].HeaderText;
                //打印背景
                graphic.FillRectangle(new SolidBrush(titleBackGroup), new Rectangle((int)currentX, (int)currentY, columnWidths[i], titleHeight));
                //打印内容
                graphic.DrawString(celValue, titleFont, titleBrush, currentX, currentY);
                //打印表格边框
                graphic.DrawRectangle(new Pen(titleBrush), new Rectangle((int)currentX, (int)currentY, columnWidths[i], titleHeight));
                currentX = currentX + columnWidths[i];
            }
            currentX = 0;
            currentY = currentY + titleHeight;

            int contentHeight = (int)Math.Ceiling(graphic.MeasureString("1e{(汗", defaultFont).Height);
            //打印内容
            for (int i = 0; i < prnDgv.Rows.Count; i++)
            {
                for (int j = 0; j < prnDgv.ColumnCount; j++)
                {
                    string celValue = prnDgv[j, i].Value.ToString();//打印内容
                    graphic.DrawString(celValue, defaultFont, defaultBrush, currentX, currentY);//打印表格边框
                    graphic.DrawRectangle(new Pen(defaultBrush), new Rectangle((int)currentX, (int)currentY, columnWidths[j], contentHeight));
                    currentX = currentX + columnWidths[j];
                }
                currentX = 0;
                currentY = currentY + contentHeight;
            }
        }
    }

调用示例代码

复制代码 代码如下:

private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
        {
            PrintCore print = new PrintCore(printDocument1, e.Graphics, new Font("宋体", 14));
            if (print.Error != null)
            {
                e.Cancel = true;
                MessageBox.Show(print.Error);
                return;
            }
            print.isCenter = true;
            print.defaultFont = new Font("宋体", 16);
            print.printString("定积分落实到减肥了减肥了圣诞节死减", true);
            print.isCenter = false;
            print.defaultFont = new Font("宋体", 14);
            print.printString("111定积分落实到减定积分落实到减肥了圣诞节死定了减肥了束带结发连锁店减肥了哦定积分落实到减肥了圣诞节死定了减肥了束带结发连锁店减肥了哦肥了圣诞节死定了减肥了束带结发连锁店减肥了哦");

            print.printDataGridView(dataGridView1,new Font("宋体", 18),Brushes.Black,DefaultBackColor);
        }

总结:以上打印有两个小问题没有处理。一个是关于分页,一个是当表格的宽度过长,超过了页面的宽度,没有进行换行处理。

另附上源码 winfrom_mrdyj_jb51net

作者:Bonker

时间: 2024-09-13 17:14:00

winfrom 打印表格 字符串的封装实现代码 附源码下载_C#教程的相关文章

基于jQuery实现交互体验社会化分享代码附源码下载_jquery

先给大家展示下效果图,看看是不是亲想要的效果,如果满足您的要求请继续往下阅读. 效果展示       源码下载 基于jQuery交互体验社会化分享代码.这是一款鼠标点击分享按钮向右滑出腾讯微博,新浪微博,QQ空间,豆瓣,微信,二维码分享等分享平台. html代码: <div style="text-align:center;font:normal 14px/24px 'MicroSoft YaHei';clear:both;width:160px;margin:0 auto;"&

仿Aspnetpager的一个PHP分页类代码 附源码下载_php实例

基本逻辑思路和.net的一样,就是将通过实体类来进行配置换成了通过数组进行配置,逻辑比较简单,根据条件判断拼接分页html. 有以下几个简单的功能: 1:支持相关按钮的显示与否配置 2:支持每页数目,文本名称,html标签类名称的自由配置 3:支持url重写过的页面(需自己在配置数组中添加重写规则) 简单吧,还是直接上代码: 核心代码:pager.class.php 复制代码 代码如下: <?php class pager{ //分页的参数配置 private $config=array( //

jQuery+CSS3+Html5实现弹出层效果实例代码(附源码下载)_jquery

弹出层用来向用户展示详细的信息,交互性非常强.弹出层有对话框.模态窗口等形式,这里我都把他们叫做弹出层,我的同事们也是这么叫的.一般我们喜欢使用比较成熟的弹出层插件如fancybox等,但在本文,我将先抛弃插件,给大家介绍如何使用jQuery+CSS3+Html5实现弹出层. 效果展示        源码下载 我们完全使用HTML5+CSS3+jQuery来实现一个基本的弹出层效果,因此我们可以在示例中任意修改弹出层外观样式.甚至js方法调用.我们最终做出来的弹出层效果应该是响应式的,也就是说可

ECharts仪表盘实例代码(附源码下载)_javascript技巧

大家在汽车驾驶舱里一眼就可以看到仪表盘,使用使用Echarts制作的仪表盘可以轻松展示用户的数据,清晰的看出某个指标值所在的范围,仪表盘形式的报表应用在各种统计系统中,本文结合实例讲解仪表盘在销售任务完成率的统计应用. 效果演示      源码下载 HTML 首先引入Echarts,然后在需要放置图表的地方加上div#myChart,同时给它加上宽度和高度属性. <script src="echarts.min.js"></script> <div id=

基于Jquery实现仿百度百科右侧导航代码附源码下载_jquery

先给大家展示下效果图,看看是不是亲想要实现的效果,如果还满意的话请查看本文详情,同时大家也可以下载源码哦. 效果图: 效果展示    源码下载 代码说明: 仿百度百科右侧导航代码jquery插件,这个仿百科右侧导航js代码,在很久以前就像搞个用了,因为这个导航特别适合长篇文档使用,花了半天时间写了这个仿百科导航插件,不过和百度百科比起来还是有点弱,没有实现右侧导航区域滚动的功能,如果您的文档不是超级变态长,应该够用. 如果你的导航超级长,可能要用到侧边导航页可以滚动,一般情况下还是用不到,等过些

基于jQuery实现仿搜狐辩论投票动画代码(附源码下载)_jquery

基于jQuery实现仿搜狐辩论投票动画代码 ,一款个性的卡通小人正方反方辩论投票特效代码.移动动画效果平滑自然.具有非常好的用户体验.该源码兼容目前最新的各类主流浏览器. 效果演示     源码下载 html代码: <script type="text/javascript"> $(document).ready(function () { var a = 500; var b = 130; $("#white").animate({ width: 0,

js网易相册特效代码附源码下载

相册效果图 相册代码  代码如下 复制代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta htt

详解 PHP加密解密字符串函数附源码下载_php实例

项目中有时我们需要使用PHP将特定的信息进行加密,也就是通过加密算法生成一个加密字符串,这个加密后的字符串可以通过解密算法进行解密,便于程序对解密后的信息进行处理. 下面先给大家展示下效果图,感兴趣的朋友继续阅读全文. 效果演示     源码下载 笔者收录了一些比较经典的PHP加密解密函数代码,分享给大家.加密解密原理一般都是通过一定的加密解密算法,将密钥加入到算法中,最终得到加密解密结果. 1.非常给力的authcode加密函数,Discuz!经典代码(带详解): function authc

jQuery实现百叶窗焦点图动画效果代码分享(附源码下载)_jquery

这是一款基于jQuery的百叶窗焦点图动画,和之前介绍的CSS3百叶窗焦点图动画不同的是,它的兼容性更好,实用性更强,因为它是基于纯jQuery的,基本上所有浏览器都能够支持.焦点图的图片切换动画是百叶窗的动画方式,但也有几种不同的百叶窗动画,因此也不会觉得单调. 在线演示     源码下载 HTML代码 <div id="slider"> <img src="images/1.jpg" alt="1" title="