C#中使用[GDI+]+PrintDocument实现打印

 近日做报表,需要实现一个比较特殊的打印:针对不同患者的药费记录,打印不同的清单,并且支持一次打印多个患者的记录。其效果看起来应该像下面这个样子:

如上所述,使用弱智的水晶报表,就会遇到如何构造数据源的问题,由于不同患者的药费记录和遗嘱记录都不同,而且整体上需要一个患者一个清单,所以其数据源只能为一个数组,而不是简单的 DataTable 。小弟一向对大且笨拙的 CrystalReport 不感冒,再加上对 GDI+ 比较痴迷,索性费点功夫,使用 GDI+ 来打印上述报表。
 
首先需要构造数据源,创建一个 ArrayList 对象 a ,然后再把每个患者需要打印的东东保存为一个 ArrayList 放入 ATotal 中。
if ( a != null )
                       {
                                a.Clear();
                       }
                       for ( int m = 0 ; m < 3 ; m ++ )
                       {
                                ArrayList a1 = new ArrayList();
                                string x0 = " 住院患者一日清单 " ;
                                string x1 = " 入院日期: 2007-11-11     结算日期: 2007-11-11 2007-11-15 " ;
                                string x2 = " 姓名:欧阳峰   住院号: 20090909090   床: 512 妇科 " ;
                                string x3 = " 项目编号 * 项目名称 * 单价 * 数量 * 单位 " ; // 注意其中的 * 标志
                                string [] x4 = new string [ 90 ]; // 假设有 90 条数据,不固定
                                for ( int i = 0 ; i < 90 ; i ++ )
                                {
                                         x4[ i ] = "juejue1984*www.loyosoft.com*11.00*11* " ; // 注意其中的 * 标志
                                }
                                string x5 = " 费用累计: 2500* 小计: 400 " ;
                                string x6 = " 累计按金: 3600* 余额: 1600 " ;
                                string x7 = "”;
                                string x8 = "”;
                                a1.Add( x0 );
                                a1.Add( x1 );
                                a1.Add( x2 );
                                a1.Add( x3 );
                                a1.Add( x4 );
                                a1.Add( x5 );
                                a1.Add( x6 );
                                a1.Add( x7 );
                                a1.Add( x8 );
a.       Add( a1 );
 
然后在 PrintDocument 对象的 PrinPage 事件作如下处理:
Size sTotal = new Size( 420, e.PageBounds.Height );
Graphics g = e.Graphics;
Font fTitle = new Font( " 宋体 ", 16 ); // 标题字体
int titleHeight = 20; // 标题的高度
int textHeight = 13; // 普通文本的高度
Font fText = new Font( " 宋体 ", 9 ); // 文本字体
 
int top = 30; // 顶部间距
int left = 10; // 左边距
int right = 10; // 右边距
int titleMargin = 15; // 标题和正文行间距
int textMargin = 5; // 行间距
int rectangleMargin = 3; // 边框和文本间距
int oneHeight = 19; // 一行文本 + 2 * 行间距的高度
int oneWidth = sTotal.Width - left - right; // 打印内容的宽度
 
int y = 0;
while ( j < a.Count ) // Count 为要打印的患者个数
{
       ArrayList a3 = a[ j ] as ArrayList; // a3 位要打印的患者的清单内容。
       if( y >= e.PageBounds.Height - titleHeight ) // 如果已经到了底部则开始下一页
       {
              e.HasMorePages = true;
              return;
       }
       //
       string x = a3[ 0 ] as string;
       if( !this.JudgeString( x ) ) // 如果此行记录还未打印过
       {
             
              //string x = " 住院患者一日清单 "; // a1
              SizeF sTitle = g.MeasureString( x, fTitle ); // 计算标题的长度和高度
              Point pTitle = new Point( ( sTotal.Width - (int)sTitle.Width ) / 2, y + top ); // 使标题绝对居中
              y += top; // 1
              //
              g.DrawString( x, fTitle, Brushes.Black, pTitle.X, y ); // 标题
              this.AddPrintedSign( ref x );
              a3[ 0 ] = x; // 标记该患者的此行内容为已经打印过
              y += titleHeight + titleMargin; // Y 坐标下移
       }
 
      
       //
       if( y >= e.PageBounds.Height - oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
 
       //// 正文第一行
       string r1 = a3[ 1 ] as String;
       if( !this.JudgeString( r1 ) )
       {
              g.DrawString( r1, fText, Brushes.Black, left, y );
              this.AddPrintedSign( ref r1 );
              a3[ 1 ] = r1;
              y += textHeight + textMargin; // 3
       }
 
       //
       if( y >= e.PageBounds.Height - oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
       //
 
       //// 正文第二行
       string r2 = a3[ 2 ] as String;
       if( !this.JudgeString( r2 ) )
       {
              g.DrawString( r2, fText, Brushes.Black, left, y );
              this.AddPrintedSign( ref r2 );
              a3[ 2 ] = r2;
              y += textHeight + textMargin; // 4
       }
 
       //
       if( y >= e.PageBounds.Height - oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
       //
 
       //// 内容
       string column = a3[ 3 ] as string;
       if( !this.JudgeString( column ) )
       {
              string[] c = column.Split( new char[] { '*' } );
              Rectangle R1 = new Rectangle( left, y, oneWidth, oneHeight );
              g.DrawRectangle( Pens.Black, R1 );
              g.DrawLine( Pens.Black, new Point( R1.X + R1.Width * 4 / 16, R1.Y ), new Point( R1.X + R1.Width * 4 / 16, R1.Y + R1.Height ) );
              g.DrawLine( Pens.Black, new Point( R1.X + R1.Width * 10 / 16, R1.Y ), new Point( R1.X + R1.Width * 10 / 16, R1.Y + R1.Height ) );
              g.DrawLine( Pens.Black, new Point( R1.X + R1.Width * 12 / 16, R1.Y ), new Point( R1.X + R1.Width * 12 / 16, R1.Y + R1.Height ) );
              g.DrawLine( Pens.Black, new Point( R1.X + R1.Width * 14 / 16, R1.Y ), new Point( R1.X + R1.Width * 14 / 16, R1.Y + R1.Height ) );
 
              g.DrawString( c[ 0 ], fText, Brushes.Black, R1.X + rectangleMargin, R1.Y + rectangleMargin ); // 项目编号 //a4.1
              g.DrawString( c[ 1 ], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 4 / 16, R1.Y + rectangleMargin );// 项目名称 // a4.2
              g.DrawString( c[ 2 ], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 10 / 16, R1.Y + rectangleMargin );// 单价 //a4.3
              g.DrawString( c[ 3 ], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 12 / 16, R1.Y + rectangleMargin ); // 数量 //a4.4
              g.DrawString( c[ 4 ], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 14 / 16, R1.Y + rectangleMargin );// 单位 //a4.5
 
 
              this.AddPrintedSign( ref column );
              a3[ 3 ] = column;
              y += oneHeight;
       }
       //
       if( y >= e.PageBounds.Height - oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
       //
 
       string[] row = a3[ 4 ] as string[];
       int Row = row.Length;
       for( int i = 0; i < Row; i ++ )
       {
              if( !this.JudgeString( row[ i ] ) )
              {
                     string[] r = row[ i ].Split( new Char[] { '*' } );
                     g.DrawLine( Pens.Black, new Point( left + oneWidth * 0 / 16, y ), new Point( left + oneWidth * 0 / 16, y + oneHeight ) );
                     g.DrawLine( Pens.Black, new Point( left + oneWidth * 4 / 16, y ), new Point( left + oneWidth * 4 / 16, y + oneHeight ) );
                     g.DrawLine( Pens.Black, new Point( left + oneWidth * 10 / 16, y ), new Point( left + oneWidth * 10 / 16, y + oneHeight ) );
                     g.DrawLine( Pens.Black, new Point( left + oneWidth * 12 / 16, y ), new Point( left + oneWidth * 12 / 16, y + oneHeight ) );
                     g.DrawLine( Pens.Black, new Point( left + oneWidth * 14 / 16, y ), new Point( left + oneWidth * 14 / 16, y + oneHeight ) );
                     g.DrawLine( Pens.Black, new Point( left + oneWidth * 16 / 16, y ), new Point( left + oneWidth * 16 / 16, y + oneHeight ) );
      
                     g.DrawString( r[ 0 ], fText, Brushes.Red, left + rectangleMargin, y + rectangleMargin ); //a5.1
                     g.DrawString( r[ 1 ], fText, Brushes.Red, left + rectangleMargin + oneWidth * 4 / 16, y + rectangleMargin ); //a5.2
                     g.DrawString( r[ 2 ], fText, Brushes.Red, left + rectangleMargin + oneWidth * 10 / 16, y + rectangleMargin );//a5.3
                     g.DrawString( r[ 3 ], fText, Brushes.Red, left + rectangleMargin + oneWidth * 12 / 16, y + rectangleMargin );//a5.4
                     g.DrawString( r[ 4 ], fText, Brushes.Red, left + rectangleMargin + oneWidth * 14 / 16, y + rectangleMargin );//a5.5
 
                     this.AddPrintedSign( ref row[ i ] );
                     y += oneHeight;
              }
              //
              if( y >= e.PageBounds.Height - oneHeight )
              {
                     e.HasMorePages = true;
                     return;
              }
              //
 
              if( i == Row - 1 )
              {
                     g.DrawLine( Pens.Black, new Point( left, y ), new Point( sTotal.Width - left - right, y ) );
              }
       }
 
       // 费用累计
       //
       if( y >= e.PageBounds.Height - oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
       //
 
       //// 费用累计
       string feeTotal = a3[ 5 ] as String;
       if( !this.JudgeString( feeTotal ) )
       {
              string[] feeT = feeTotal.Split( new char[] { '*' } );
              Rectangle R3 = new Rectangle( left, y, oneWidth, oneHeight );
              g.DrawRectangle( Pens.Black, R3 );
              g.DrawLine( Pens.Black, new Point( left + oneWidth * 10 / 16, y ), new Point( left + oneWidth * 10 / 16, y + R3.Height ) );
              g.DrawString( feeT[ 0 ], fText, Brushes.Black, R3.X + rectangleMargin, y + rectangleMargin );
              g.DrawString( feeT[ 1 ], fText, Brushes.Black, left + 2 * rectangleMargin + R3.Width * 10 / 16, y + rectangleMargin );
              this.AddPrintedSign( ref feeTotal );
              a3[ 5 ] = feeTotal;
              y += oneHeight;
       }
 
       //
       if( y >= e.PageBounds.Height - oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
       //
 
       //// 费用按金
       string feeBalance = a3[ 6 ] as String;
       if( !this.JudgeString( feeBalance ) )
       {
              string[] feeB = feeBalance.Split( new char[] { '*' } );
              Rectangle R4 = new Rectangle( left, y, oneWidth, oneHeight );
              g.DrawRectangle( Pens.Black, R4 );
              g.DrawLine( Pens.Black, new Point( left + oneWidth * 10 / 16, y ), new Point( left + oneWidth * 10 / 16, y + R4.Height ) );
              g.DrawString( feeB[ 0 ], fText, Brushes.Black, left + rectangleMargin, y + rectangleMargin );
              g.DrawString( feeB[ 1 ], fText, Brushes.Black, left + 2 * rectangleMargin + oneWidth * 10 / 16, y + rectangleMargin );
 
              this.AddPrintedSign( ref feeBalance );
              a3[ 6 ] = feeBalance;
              y += oneHeight;
       }
 
 
       //// 备注
       //string remark = "  备注:此清单一式两份,正联由患者或者家属签字,科室留存,付联由患者保存,可随时查询。如 24 小时不签字,不质疑视为认可费用。如病情需要变更医嘱另行通知。 /r/n" +
       //     "         注:省保或者市保的比例为自费比例。 ";
       string remark1 = a3[ 7 ] as String;
      
       SizeF remarkSize = g.MeasureString( remark1, fText );
       int Row2 = ( int )remarkSize.Width / ( oneWidth - 2 * rectangleMargin );
       if( Row2 * ( oneWidth - 2 * rectangleMargin ) < (int)remarkSize.Width )
       {
              Row2 += 1;
       }
       //
       if( y >= e.PageBounds.Height - ( Row2 + 1 ) * textHeight + 2 * rectangleMargin + Row2 * textMargin )
       {
              e.HasMorePages = true;
              return;
       }
       //
       if( !this.JudgeString( remark1 ) )
       {
              Rectangle R5 = new Rectangle( left, y, oneWidth, ( Row2 + 1 ) * textHeight + 2 * rectangleMargin + Row2 * textMargin );
              g.DrawRectangle( Pens.Black, R5 );
              R5.Offset( 2, 5 );
              g.DrawString( remark1, fText, Brushes.Black, R5 );
              this.AddPrintedSign( ref remark1 );
              a3[ 7 ] = remark1;
              y += R5.Height;
       }
 
       //
       if( y >= e.PageBounds.Height - 3 * oneHeight )
       {
              e.HasMorePages = true;
              return;
       }
 
       //// 签字
       string signature = a3[ 8 ] as String;
       Rectangle R6 = new Rectangle( left, y, oneWidth, 2 * rectangleMargin + 3 * textHeight + 2 * textMargin );
       if( !this.JudgeString( signature ) )
       {
              g.DrawRectangle( Pens.Black, R6 );
              g.DrawString( signature, fText, Brushes.Black, left, y + rectangleMargin + textMargin + textHeight );
              this.AddPrintedSign( ref signature );
              a3[ 8 ] = signature;
              y += R6.Height;
       }
       j ++;
       }
      j = 0; // 打印完毕
     e.HasMorePages = false;
}
 
判断一行内容是否已经打印过:
/// <summary>
/// 判断该字符串最后一个字符是否是 * 号,如果是,则表示已经打印过
/// </summary>
/// <param name="s"> 需要判断的字符串 </param>
/// <returns> 如果有则返回 true ,否则返回 false</returns>
private bool JudgeString( string s )
{
       int l = s.Length;
       if( s[ l - 1 ] != '*' )
       {
              return false;
       }
       return true;
}
 
将已经打印过的内容标记为已打印
/// <summary>
/// 将已经打印过的行最后一个字符标记为 * ,表示该行已经打印
/// </summary>
/// <param name="s"> 字符串对象 </param>
private void AddPrintedSign( ref string s )
{
       int l = s.Length;
       s = s.Replace( s.Substring( l - 1, 1 ), "*" );
}
 

你可能感兴趣的:(c,String,C#,null,报表,GDI+)