C#中使用GDI+实现复杂打印

 

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

 

 

 

如上所述,使用弱智的水晶报表,就会遇到如何构造数据源的问题,由于不同患者的药费记录和遗嘱记录都不同,而且整体上需要一个患者一个清单,所以其数据源只能为一个数组,而不是简单的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 );

  1. 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 ), "*" );

}

 

posted @ 2012-04-09 12:01  潇湘〃细雨  阅读(1087)  评论(2编辑  收藏  举报