C#打印服务

15 篇文章 0 订阅
  Winform里集成了几个打印控件: PrintPreviewDialog PrintDocument , PrintDialog , PageSetupDialog , PrintPreviewControl ,看书看资料会把人看晕,实际上打印核心控件只有一个,就是 PrintDocument PrintPreviewDialog 也有点用,就是页面预览控件,真正开发中如果需要打印功能,一般会从网上Down现成的控件,如果要自己手动写,费时又费力,本着学习的态度,我们需要知道打印是怎么实现的,写两个比较常用的打印服务,一个是打印 DataTable 的,另一个是打印 TextBox 的。
             示例一:以表格形式打印DataTable内的数据
[csharp]  view plain copy
  1. //定义全局变量count,储存当前打印的行数  
  2.   
  3. int count=0;  
  4.   
  5. //定义一个方法,接收一个DataTable类型参数及PrintDocument的PrintPage事件传入的参数e以方便操作  
  6.   
  7. private void PrintTable(DataTable dt, System.Drawing.Printing.PrintPageEventArgs e)  
  8. {   
  9.   
  10.       //取得对应的Graphics对象            
  11.       Graphics g = e.Graphics;  
  12.   
  13.       //获得相关页面X坐标、Y坐标、打印区域宽度、长度  
  14.       int x = e.PageSettings.Margins.Left;  
  15.       int y = e.PageSettings.Margins.Top;  
  16.       int width = e.PageSettings.PaperSize.Width -e.PageSettings.Margins.Left - e.PageSettings.Margins.Right;  
  17.       int height = e.PageSettings.PaperSize.Height - e.PageSettings.Margins.Top - e.PageSettings.Margins.Bottom;  
  18.   
  19.       //定义打印字体  
  20.       Font font = new Font("宋体",15);  
  21.   
  22.       //rowCount是除去打印过的行数后剩下的行数  
  23.       int rowCount = dt.Rows.Count-count;  
  24.   
  25.       //maxPageRow是当前设置下该页面可以打印的最大行数  
  26.       int maxPageRow=height/(int)font.GetHeight();  
  27.   
  28.       //因为是表格,先画一条水平直线  
  29.       g.DrawLine(new Pen(Brushes.Black, 1), new Point(x, y), new Point(x + (dt.Columns.Count) * 135, y));  
  30.   
  31.       //再画出表格各列的列标题  
  32.       for (int i = 0; i < dt.Columns.Count; i++)  
  33.       {  
  34.           string head = dt.Columns[i].ColumnName;  
  35.           g.DrawString(head, font, Brushes.Black, x + i * 135, y);  
  36.       }  
  37.   
  38.       //画完标题,再画一条直线  
  39.       g.DrawLine(new Pen(Brushes.Black, 1), new Point(x, y + (int)font.GetHeight()), new Point(x + (dt.Columns.Count) * 135, y + (int)font.GetHeight()));  
  40.   
  41.       //判断,如果剩下的行数小于可打印的最大行数,则执行下列代码  
  42.       if (maxPageRow >= rowCount)  
  43.       {  
  44.           //当前行数小于Table内总行数时,循环  
  45.           while (count < dt.Rows.Count)  
  46.           {  
  47.   
  48.               //内循环打印Table内行数据  
  49.               int columnCount = 0;  
  50.               while (columnCount < dt.Columns.Count)  
  51.               {  
  52.                   string temp = dt.Rows[count][columnCount].ToString();  
  53.   
  54.                   //打印每个单元格内的数据  
  55.                   g.DrawString(temp, font, Brushes.Black, x + columnCount * 135, y + (count % maxPageRow) * (int)font.GetHeight() + (int)font.GetHeight());  
  56.   
  57.                   //打印完一行后,继续打印一条直线  
  58.                   g.DrawLine(new Pen(Brushes.Black, 1), new Point(x, y + (count % maxPageRow) * (int)font.GetHeight() + 2 * (int)font.GetHeight()), new Point(x + (dt.Columns.Count) * 135, y + (count % maxPageRow) * (int)font.GetHeight() + 2 * (int)font.GetHeight()));  
  59.                   columnCount++;  
  60.              }  
  61.               count++;  
  62.           }  
  63.   
  64.           //所有数据打印完毕后,打印垂直直线                 
  65.   
  66.           for (int i = 0; i <= dt.Columns.Count; i++)  
  67.           {  
  68.               g.DrawLine(new Pen(Brushes.Black), new Point(x + i * 135, y), new Point(x + i * 135, y + rowCount * (int)font.GetHeight() + (int)font.GetHeight()));  
  69.           }  
  70.       }  
  71.   
  72.       //判断,如果剩下的行数大于可打印的最大行数,则执行下列代码  
  73.       else  
  74.       {  
  75.           do  
  76.           {  
  77.   
  78.               //与上面类似,注意下面while的条件  
  79.               int columnCount = 0;  
  80.               while (columnCount < dt.Columns.Count)  
  81.               {  
  82.                   string temp = dt.Rows[count][columnCount].ToString();  
  83.   
  84.                   //打印每个单元格  
  85.                   g.DrawString(temp, font, Brushes.Black, x + columnCount * 135, y + (count % maxPageRow) * (int)font.GetHeight() + (int)font.GetHeight());  
  86.   
  87.                   //打印水平直线  
  88.                   g.DrawLine(new Pen(Brushes.Black, 1), new Point(x, y + (count % maxPageRow) * (int)font.GetHeight() + 2 * (int)font.GetHeight()), new Point(x + (dt.Columns.Count)*135, y + (count % maxPageRow) * (int)font.GetHeight() + 2 * (int)font.GetHeight()));  
  89.                   columnCount++;  
  90.               }  
  91.               count++;  
  92.           } while ((count % maxPageRow > 0));  
  93.   
  94.           //打印垂直直线  
  95.           for (int i = 0; i <= dt.Columns.Count;i++ )  
  96.           {  
  97.               g.DrawLine(new Pen(Brushes.Black), new Point(x + i * 135, y), new Point(x + i * 135, y + height + (int)font.GetHeight()));  
  98.           }  
  99.   
  100.       }  
  101.   
  102.       //指定HasMorePages值,如果页面最大行数小于剩下的行数,则返回true(还有),否则返回false  
  103.       if (maxPageRow<rowCount)  
  104.       {  
  105.           e.HasMorePages = true;  
  106.       }  
  107.       else  
  108.       {  
  109.           e.HasMorePages = false;  
  110.           count = 0;  
  111.       }  
  112.    }  

 

         奇长无比,打印的原理就是画,所有东西都是画出来的,大体思路就是这样,其他的无非就是计算跟调整间距问题,多试几次不难,我觉得最难的部分是循环取值及设置HasMorePages属性,PrintDocumentPrintPage方法是打印完一页调用一次,因此当自己做打印设置时,需要清楚的知道哪些变量需要储存为全局变量以方便记录打印位置,HasMorePages属性也需要注意,是不是只需要一个条件就可以指定其值,很多情况下需要多个条件同时满足,另外对画表格这种事情来说,前几页跟最后一页while里条件写法肯定是不同的,写一起就乱套了,最后,在给HasMorePages设置为false后,不要忘记把你的全局变量恢复初始值,否则连点两下打印预览就没数据了,以上是A4大小,如果只实现简单打印,这样足够了,如果设计到调整页面,设置字体等等,抱歉,做不了,这就需要网上DOWN现成的了。下一个说说TextBox里的文本打印。

            示例二:文本打印
[csharp]  view plain copy
  1. //设置全局变量保存截取字符串位置  
  2.   
  3. int sub=0;  
  4.   
  5. private void printText(string text, System.Drawing.Printing.PrintPageEventArgs e)  
  6.         {            
  7.             //取得Graphics实例  
  8.             Graphics g = e.Graphics;  
  9.   
  10.             //获得相关点坐标、长度、宽度  
  11.             int x = e.PageSettings.Margins.Left;  
  12.             int y = e.PageSettings.Margins.Right;  
  13.             int width = e.PageSettings.PaperSize.Width-e.PageSettings.Margins.Left-e.PageSettings.Margins.Right;  
  14.             int height = e.PageSettings.PaperSize.Height-e.PageSettings.Margins.Top-e.PageSettings.Margins.Bottom;  
  15.   
  16.             //设置字体  
  17.             Font font=new Font("宋体",15);  
  18.   
  19.             //这个方法后面讲  
  20.   
  21.             g.MeasureString(text.Substring(sub), font, new SizeF(width, height-10), new StringFormat(), out charnum, out line);  
  22.   
  23.             //打印string           
  24.             g.DrawString(text.Substring(sub), font, Brushes.Black, new RectangleF(x, y, width, height), new StringFormat());           
  25.   
  26.             //设置截取位置  
  27.             sub += charnum;  
  28.   
  29.             //设置HasMorePage属性  
  30.             if (sub < this.txtText.Text.Length)  
  31.             {  
  32.                 e.HasMorePages = true;  
  33.             }  
  34.             else  
  35.             {  
  36.                 e.HasMorePages = false;  
  37.   
  38.                 sub=0;  
  39.             }  
  40.         }  


         注意问题有这么几点,MeasureString方法单独拿出来说,此方法的通俗理解就是,把一个字符串按照指定的矩形区域、字符串格式、字体选取,并在选取后将字符数量,所需行数保存在两个out int变量中,第一个参数,需要操作的字符串;第二个,字体;第三个,区域;第四个,字符串的格式化样式;第五个,字符个数;第六个,所需行数。注意的是两个out int类型的参数,这里跟ref类型差不多,当传递参数的时候,实际传递的是参数的地址,因此在方法内部对参数做了修改之后,会反应到源数据上,因此在执行完这个方法后,你所传递进来的两个参数已经保存了相关信息。DrawString方法也使用了其中一个带有RectangleF参数的重载方法,目的是与MeasureString相吻合,注意我划线几个地方的写法,注意MeasureString中第一个参数string同样需要截取。

            两个例子说完了,下面说说怎么调用打印方法:

[csharp]  view plain copy
  1. //打印预览  
  2.   
  3. private void button2_Click(object sender, EventArgs e)  
  4.         {  
  5.   
  6.             //注意指定其Document属性  
  7.             this.printPreviewDialog1.Document = this.printDocument1;  
  8.             this.printPreviewDialog1.ShowDialog();  
  9.         }   
  10.   
  11. //打印  
  12.   
  13.  private void button1_Click(object sender, EventArgs e)  
  14.         {  
  15.   
  16.             //同样注意指定Document属性  
  17.             this.printDialog1.Document = this.printDocument1;  
  18.             if (this.printDialog1.ShowDialog() == DialogResult.OK)  
  19.             {  
  20.   
  21.                 //触发PrintDocument的PrintPage事件  
  22.                 this.printDocument1.Print();  
  23.             }  
  24.         }  


OK,关于打印就小小的说完了,不怎么重要,掌握原理即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值