zoukankan      html  css  js  c++  java
  • C#中使用GDI+与PrintDocument实现打印

    近日做报表,需要实现一个比较特殊的打印:针对不同患者的药费记录,打印不同的清单,并且支持一次打印多个患者的记录。其效果看起来应该像下面这个样子:
          如上所述,使用弱智的水晶报表,就会遇到如何构造数据源的问题,由于不同患者的药费记录和遗嘱记录都不同,而且整体上需要一个患者一个清单,所以其数据源只能为一个数组,而不是简单的DataTable。小弟一向对大且笨拙的CrystalReport不感冒,再加上对GDI+比较痴迷,索性费点功夫,使用GDI+来打印上述报表。
         首先需要构造数据源,创建一个ArrayList对象a,然后再把每个患者需要打印的东东保存为一个ArrayList放入ATotal中。
     1if (a != null)
     2{
     3    a.Clear();
     4}

     5for (int m = 0; m < 3; m++)
     6{
     7    ArrayList a1 = new ArrayList();
     8    string x0 = "住院患者一日清单";
     9    string x1 = "入院日期:2007-11-11    结算日期:2007-11-11至 2007-11-15 ";
    10    string x2 = "姓名:欧阳峰 住院号:20090909090   床:512 妇科";
    11    string x3 = "项目编号*项目名称*单价*数量*单位"// 注意其中的*标志
    12    string[] x4 = newstring[90]; // 假设有90条数据,不固定
    13    for (int i = 0; i < 90; i++)
    14    {
    15        x4[i] = "juejue1984*www.loyosoft.com*11.00*11*鸟"// 注意其中的*标志
    16    }

    17    string x5 = "费用累计:2500*小计:400 ";
    18    string x6 = "累计按金:3600*余额:1600 ";
    19    string x7 = "";
    20    string x8 = "";
    21    a1.Add(x0);
    22    a1.Add(x1);
    23    a1.Add(x2);
    24    a1.Add(x3);
    25    a1.Add(x4);
    26    a1.Add(x5);
    27    a1.Add(x6);
    28    a1.Add(x7);
    29    a1.Add(x8);
    30    a.Add(a1);
    31}

    然后在PrintDocument对象的PrinPage事件作如下处理:

      1Size sTotal = new Size(420, e.PageBounds.Height);
      2Graphics g = e.Graphics;
      3Font fTitle = new Font("宋体"16); // 标题字体
      4int titleHeight = 20// 标题的高度
      5int textHeight = 13// 普通文本的高度
      6Font fText = new Font("宋体"9); // 文本字体
      7
      8int top = 30// 顶部间距
      9int left = 10// 左边距
     10int right = 10// 右边距
     11int titleMargin = 15// 标题和正文行间距
     12int textMargin = 5// 行间距
     13int rectangleMargin = 3// 边框和文本间距
     14int oneHeight = 19// 一行文本 + 2 * 行间距的高度
     15int oneWidth = sTotal.Width - left - right; // 打印内容的宽度
     16
     17int y = 0;
     18while (j < a.Count) // Count为要打印的患者个数
     19{
     20    ArrayList a3 = a[j] as ArrayList; // a3位要打印的患者的清单内容。
     21    if (y >= e.PageBounds.Height - titleHeight) // 如果已经到了底部则开始下一页
     22    {
     23e.HasMorePages = true;
     24return;
     25    }

     26    //
     27    string x = a3[0as string;
     28    if (!this.JudgeString(x)) // 如果此行记录还未打印过
     29    {
     30
     31//string x = "住院患者一日清单"; // a1
     32SizeF sTitle = g.MeasureString(x, fTitle); // 计算标题的长度和高度
     33Point pTitle = new Point((sTotal.Width - (int)sTitle.Width) / 2, y + top); // 使标题绝对居中
     34+= top; // 1
     35//
     36g.DrawString(x, fTitle, Brushes.Black, pTitle.X, y); // 标题
     37this.AddPrintedSign(ref x);
     38a3[0= x; // 标记该患者的此行内容为已经打印过
     39+= titleHeight + titleMargin; // Y坐标下移
     40    }

     41
     42
     43    //
     44    if (y >= e.PageBounds.Height - oneHeight)
     45    {
     46e.HasMorePages = true;
     47return;
     48    }

     49
     50    //// 正文第一行
     51    string r1 = a3[1as String;
     52    if (!this.JudgeString(r1))
     53    {
     54g.DrawString(r1, fText, Brushes.Black, left, y);
     55this.AddPrintedSign(ref r1);
     56a3[1= r1;
     57+= textHeight + textMargin; // 3
     58    }

     59
     60    //
     61    if (y >= e.PageBounds.Height - oneHeight)
     62    {
     63e.HasMorePages = true;
     64return;
     65    }

     66    //
     67
     68    //// 正文第二行
     69    string r2 = a3[2as String;
     70    if (!this.JudgeString(r2))
     71    {
     72g.DrawString(r2, fText, Brushes.Black, left, y);
     73this.AddPrintedSign(ref r2);
     74a3[2= r2;
     75+= textHeight + textMargin; // 4
     76    }

     77
     78    //
     79    if (y >= e.PageBounds.Height - oneHeight)
     80    {
     81e.HasMorePages = true;
     82return;
     83    }

     84    //
     85
     86    ////内容
     87    string column = a3[3as string;
     88    if (!this.JudgeString(column))
     89    {
     90string[] c = column.Split(new char[] '*' });
     91Rectangle R1 = new Rectangle(left, y, oneWidth, oneHeight);
     92g.DrawRectangle(Pens.Black, R1);
     93g.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));
     94g.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));
     95g.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));
     96g.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));
     97
     98g.DrawString(c[0], fText, Brushes.Black, R1.X + rectangleMargin, R1.Y + rectangleMargin); // 项目编号 //a4.1
     99g.DrawString(c[1], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 4 / 16, R1.Y + rectangleMargin);// 项目名称 // a4.2
    100g.DrawString(c[2], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 10 / 16, R1.Y + rectangleMargin);//单价 //a4.3
    101g.DrawString(c[3], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 12 / 16, R1.Y + rectangleMargin); //数量 //a4.4
    102g.DrawString(c[4], fText, Brushes.Black, R1.X + rectangleMargin + R1.Width * 14 / 16, R1.Y + rectangleMargin);//单位 //a4.5
    103
    104
    105this.AddPrintedSign(ref column);
    106a3[3= column;
    107+= oneHeight;
    108    }

    109    //
    110    if (y >= e.PageBounds.Height - oneHeight)
    111    {
    112e.HasMorePages = true;
    113return;
    114    }

    115    //
    116
    117    string[] row = a3[4as string[];
    118    int Row = row.Length;
    119    for (int i = 0; i < Row; i++)
    120    {
    121if (!this.JudgeString(row[i]))
    122{
    123    string[] r = row[i].Split(new Char[] '*' });
    124    g.DrawLine(Pens.Black, new Point(left + oneWidth * 0 / 16, y), new Point(left + oneWidth * 0 / 16, y + oneHeight));
    125    g.DrawLine(Pens.Black, new Point(left + oneWidth * 4 / 16, y), new Point(left + oneWidth * 4 / 16, y + oneHeight));
    126    g.DrawLine(Pens.Black, new Point(left + oneWidth * 10 / 16, y), new Point(left + oneWidth * 10 / 16, y + oneHeight));
    127    g.DrawLine(Pens.Black, new Point(left + oneWidth * 12 / 16, y), new Point(left + oneWidth * 12 / 16, y + oneHeight));
    128    g.DrawLine(Pens.Black, new Point(left + oneWidth * 14 / 16, y), new Point(left + oneWidth * 14 / 16, y + oneHeight));
    129    g.DrawLine(Pens.Black, new Point(left + oneWidth * 16 / 16, y), new Point(left + oneWidth * 16 / 16, y + oneHeight));
    130
    131    g.DrawString(r[0], fText, Brushes.Red, left + rectangleMargin, y + rectangleMargin); //a5.1
    132    g.DrawString(r[1], fText, Brushes.Red, left + rectangleMargin + oneWidth * 4 / 16, y + rectangleMargin); //a5.2
    133    g.DrawString(r[2], fText, Brushes.Red, left + rectangleMargin + oneWidth * 10 / 16, y + rectangleMargin);//a5.3
    134    g.DrawString(r[3], fText, Brushes.Red, left + rectangleMargin + oneWidth * 12 / 16, y + rectangleMargin);//a5.4
    135    g.DrawString(r[4], fText, Brushes.Red, left + rectangleMargin + oneWidth * 14 / 16, y + rectangleMargin);//a5.5
    136
    137    this.AddPrintedSign(ref row[i]);
    138    y += oneHeight;
    139}

    140//
    141if (y >= e.PageBounds.Height - oneHeight)
    142{
    143    e.HasMorePages = true;
    144    return;
    145}

    146//
    147
    148if (i == Row - 1)
    149{
    150    g.DrawLine(Pens.Black, new Point(left, y), new Point(sTotal.Width - left - right, y));
    151}

    152    }

    153
    154    //费用累计
    155    //
    156    if (y >= e.PageBounds.Height - oneHeight)
    157    {
    158e.HasMorePages = true;
    159return;
    160    }

    161    //
    162
    163    ////费用累计
    164    string feeTotal = a3[5as String;
    165    if (!this.JudgeString(feeTotal))
    166    {
    167string[] feeT = feeTotal.Split(new char[] '*' });
    168Rectangle R3 = new Rectangle(left, y, oneWidth, oneHeight);
    169g.DrawRectangle(Pens.Black, R3);
    170g.DrawLine(Pens.Black, new Point(left + oneWidth * 10 / 16, y), new Point(left + oneWidth * 10 / 16, y + R3.Height));
    171g.DrawString(feeT[0], fText, Brushes.Black, R3.X + rectangleMargin, y + rectangleMargin);
    172g.DrawString(feeT[1], fText, Brushes.Black, left + 2 * rectangleMargin + R3.Width * 10 / 16, y + rectangleMargin);
    173this.AddPrintedSign(ref feeTotal);
    174a3[5= feeTotal;
    175+= oneHeight;
    176    }

    177
    178    //
    179    if (y >= e.PageBounds.Height - oneHeight)
    180    {
    181e.HasMorePages = true;
    182return;
    183    }

    184    //
    185
    186    ////费用按金
    187    string feeBalance = a3[6as String;
    188    if (!this.JudgeString(feeBalance))
    189    {
    190string[] feeB = feeBalance.Split(new char[] '*' });
    191Rectangle R4 = new Rectangle(left, y, oneWidth, oneHeight);
    192g.DrawRectangle(Pens.Black, R4);
    193g.DrawLine(Pens.Black, new Point(left + oneWidth * 10 / 16, y), new Point(left + oneWidth * 10 / 16, y + R4.Height));
    194g.DrawString(feeB[0], fText, Brushes.Black, left + rectangleMargin, y + rectangleMargin);
    195g.DrawString(feeB[1], fText, Brushes.Black, left + 2 * rectangleMargin + oneWidth * 10 / 16, y + rectangleMargin);
    196
    197this.AddPrintedSign(ref feeBalance);
    198a3[6= feeBalance;
    199+= oneHeight;
    200    }

    201
    202
    203    //// 备注
    204    //string remark = " 备注:此清单一式两份,正联由患者或者家属签字,科室留存,付联由患者保存,可随时查询。如24小时不签字,不质疑视为认可费用。如病情需要变更医嘱另行通知。\r\n" + 
    205    //     " 注:省保或者市保的比例为自费比例。";
    206    string remark1 = a3[7as String;
    207
    208    SizeF remarkSize = g.MeasureString(remark1, fText);
    209    int Row2 = (int)remarkSize.Width / (oneWidth - 2 * rectangleMargin);
    210    if (Row2 * (oneWidth - 2 * rectangleMargin) < (int)remarkSize.Width)
    211    {
    212Row2 += 1;
    213    }

    214    //
    215    if (y >= e.PageBounds.Height - (Row2 + 1* textHeight + 2 * rectangleMargin + Row2 * textMargin)
    216    {
    217e.HasMorePages = true;
    218return;
    219    }

    220    //
    221    if (!this.JudgeString(remark1))
    222    {
    223Rectangle R5 = new Rectangle(left, y, oneWidth, (Row2 + 1* textHeight + 2 * rectangleMargin + Row2 * textMargin);
    224g.DrawRectangle(Pens.Black, R5);
    225R5.Offset(25);
    226g.DrawString(remark1, fText, Brushes.Black, R5);
    227this.AddPrintedSign(ref remark1);
    228a3[7= remark1;
    229+= R5.Height;
    230    }

    231
    232    //
    233    if (y >= e.PageBounds.Height - 3 * oneHeight)
    234    {
    235e.HasMorePages = true;
    236return;
    237    }

    238
    239    ////签字
    240    string signature = a3[8as String;
    241    Rectangle R6 = new Rectangle(left, y, oneWidth, 2 * rectangleMargin + 3 * textHeight + 2 * textMargin);
    242    if (!this.JudgeString(signature))
    243    {
    244g.DrawRectangle(Pens.Black, R6);
    245g.DrawString(signature, fText, Brushes.Black, left, y + rectangleMargin + textMargin + textHeight);
    246this.AddPrintedSign(ref signature);
    247a3[8= signature;
    248+= R6.Height;
    249    }

    250    j++;
    251}

    252= 0// 打印完毕
    253e.HasMorePages = false;

    判断一行内容是否已经打印过:

     1/// <summary>
     2/// 判断该字符串最后一个字符是否是 * 号,如果是,则表示已经打印过
     3/// </summary>
     4/// <param name="s">需要判断的字符串</param>
     5/// <returns>如果有则返回true,否则返回false</returns>

     6private bool JudgeString( string s )
     7{
     8    int l = s.Length;
     9    if( s[ l - 1 ] != '*' )
    10    {
    11      return false;
    12    }

    13    return true;
    14}

    15 
    16将已经打印过的内容标记为已打印
    17/// <summary>
    18/// 将已经打印过的行最后一个字符标记为*,表示该行已经打印
    19/// </summary>
    20/// <param name="s">字符串对象</param>

    21private void AddPrintedSign( ref string s )
    22{
    23    int l = s.Length;
    24    s = s.Replace( s.Substring( l - 11 ), "*" );
    25}

  • 相关阅读:
    行为的封装
    分页功能-----》链表实现
    python入门教程链接
    作用域 属性链接 存储类型
    Codeforces Round #598 (Div. 3)
    CCPC2018-湖南全国邀请赛
    【洛谷P2494】 [SDOI2011]保密(分数规划+最小割)
    【洛谷P3329】 [ZJOI2011]最小割(最小割树)
    【BZOJ3716】[PA2014]Muzeum(贪心+网络流)
    【洛谷P4542】 [ZJOI2011]营救皮卡丘(费用流)
  • 原文地址:https://www.cnblogs.com/moss_tan_jun/p/2051484.html
Copyright © 2011-2022 走看看