zoukankan      html  css  js  c++  java
  • 组装所有单元格数据后,计算需要合并的单元格数据

    在进行pdf报表的绘制过程中,报表基本都是表格形式的,会有合并行、列的情况,使用的是itextsharp组件;
    之前表格的单元格合并和业务是耦合在一起的,都需要开发人员每次绘制表格时,自己用各种办法合并单元格,还需要考虑分页的情况,需要开发人员有较强的逻辑分析能力、足够细致才不会有很多bug,且开发周期长。
    在熟悉相关业务之后,我觉得可以把计算单元格的合并和业务分页,开发人员只需关心数据如何组装,单元格的合并及分页由系统自动完成,可以提升开发速度及质量,具体思路如下:
     
    1、组装所有单元格数据(X坐标、Y坐标、单元格内容、是否允许合并、合并单元格时的判断依据的值、合并的行数、合并的列数)。
    2、逐行遍历,计算每一行中需要合并的单元格,返回合并后的单元格列表(包含合并了的,以及未合并但需要合并的单元格)。
    3、对上一个方法返回的结果逐列遍历,计算每一列中需要合并的单元格,最终返回所有需要合并的单元格数据列表。
    4、用原始的单元格数据,一行一行地把单元格数据画到pdf上,画每一个单元格的时候,判断一下该单元格是否被合并了,如果被合并了就先不画;
    等到一页pdf画满之后,用这一页的所有单元格数据再组成一个集合,重新计算一下当前页需要合并的单元格数据,然后画到pdf上即可。
    5、然后再拿到剩余的没绘制的单元格数据,重复2、3、4,直至把所有单元格都绘制到pdf上。
     
    这里只展示一下计算单元格的合并的代码:
      1 /// <summary>
      2 /// 根据源数据生成所有合并的单元格信息
      3 /// </summary>
      4 /// <param name="originalData"></param>
      5 /// <returns></returns>
      6 public static List<CellInfo> GenerateMergeCellList(List<CellInfo> originalData)
      7 {
      8     if (originalData == null || !originalData.Any())
      9     {
     10         return new List<CellInfo>();
     11     }
     12     int maxRowCount = originalData.Max(c => c.XNum);//最大行号下标
     13     Dictionary<int, List<CellInfo>> rowMergeResult = new Dictionary<int, List<CellInfo>>();
     14     for (int i = 0; i <= maxRowCount; i++)
     15     {
     16         List<CellInfo> currentRowData = originalData.Where(c => c.XNum == i).ToList();//当前这一行数据
     17         List<CellInfo> rowResult = GenerateRowMergeInfo(currentRowData).ToList();//生成这一行的单元格信息,不包含不允许合并的单元格
     18         rowMergeResult.Add(i, rowResult);
     19     }
     20     List<CellInfo> mergeResult = GenerateMergeInfo(rowMergeResult);
     21     return mergeResult;
     22 }
     23 
     24 /// <summary>
     25 /// 把某一行单元格集合传进去
     26 /// 对单元格进行合并计算,返回需要进行列合并计算的单元格集合
     27 /// </summary>
     28 /// <param name="originalCellList">当前行的数据集合</param>
     29 /// <returns>包含已经合并了的单元格信息以及需要进行列合并计算的单元格信息</returns>
     30 private static List<CellInfo> GenerateRowMergeInfo(List<CellInfo> originalCellList)
     31 {
     32     if (originalCellList == null || !originalCellList.Any())
     33     {
     34         return new List<CellInfo>();
     35     }
     36     int rowIndex = originalCellList.Any() ? originalCellList.First().XNum : 0;
     37     List<string> contentList = originalCellList.OrderBy(c => c.YNum).Select(c => c.Content).ToList();//把这一行数据组成一个string串
     38     List<CellInfo> result = new List<CellInfo>();
     39     int colspan;//要合并的列数
     40 
     41     for (int i = 0; i < contentList.Count; i++)
     42     {
     43         colspan = 1;
     44         if (!originalCellList.Single(c => c.YNum == i).AllowMerge)//不允许合并的,直接continue
     45         {
     46             continue;
     47         }
     48 
     49         //非最后一个单元格,且当前单元格与下一个单元格内容一致,需要计算一下要合并的单元格
     50         //如果是最后一个单元格,就不需要判断是否与下一个单元格内容一致了,直接添加到结果数据中
     51         if (i < (contentList.Count - 1) && contentList[i] == contentList[i + 1])//表示当前值和下一个值是相同的
     52         {
     53             while (i < contentList.Count - 1)
     54             {
     55                 if (contentList[i] == contentList[i + 1])
     56                 {
     57                     ++i;
     58                     ++colspan;
     59                 }
     60                 else
     61                 {
     62                     break;
     63                 }
     64             }
     65         }
     66         CellInfo originalCellFirst = originalCellList.Single(c => c.YNum == (i - colspan + 1));
     67         result.Add(new CellInfo()
     68         {
     69             XNum = rowIndex,
     70             YNum = originalCellFirst.YNum,
     71             Content = originalCellFirst.Content,
     72             DrawContent = originalCellFirst.DrawContent,
     73             Colspan = colspan
     74         });
     75     }
     76     return result;
     77 }
     78 
     79 /// <summary>
     80 /// 生成所有合并的单元格信息
     81 /// </summary>
     82 /// <param name="rowMergeResult">一行一行的单元格数据集合</param>
     83 /// <returns></returns>
     84 private static List<CellInfo> GenerateMergeInfo(Dictionary<int, List<CellInfo>> rowMergeResult)
     85 {
     86     List<CellInfo> result = new List<CellInfo>();
     87     int rowspan;
     88     int index;
     89     CellInfo currentRowCell;
     90     CellInfo startRowCell;
     91     CellInfo nextRowCell;
     92     for (int i = 0; i < rowMergeResult.Count; i++)//循环行
     93     {
     94         for (int j = 0; j < rowMergeResult[i].Count; j++)//循环列
     95         {
     96             rowspan = 1;
     97             currentRowCell = rowMergeResult[i][j];//当前单元格
     98             startRowCell = rowMergeResult[i][j];//初始单元格
     99             if (IsContainedMergeCell(result, currentRowCell) || !currentRowCell.AllowMerge)//单元格已经被合并时,不处理
    100             {
    101                 continue;
    102             }
    103             if (i == rowMergeResult.Count - 1)//最后一行时,直接加到结果集中了(在最后一行会排除掉不合并的单元格)
    104             {
    105                 result.Add(startRowCell);
    106                 continue;
    107             }
    108 
    109             nextRowCell = rowMergeResult[i + 1].FirstOrDefault(r => r.YNum == currentRowCell.YNum && r.Content == currentRowCell.Content && r.Colspan == currentRowCell.Colspan && r.AllowMerge);
    110             if (nextRowCell == null)//如果该单元格在竖直方向上不需要合并,即rowspan保持不变
    111             {
    112                 result.Add(startRowCell);
    113                 continue;
    114             }
    115             index = 0;//遍历的行数
    116             while ((i + index) < rowMergeResult.Count - 1)//循环到倒数第二行
    117             {
    118                 index++;
    119                 nextRowCell = rowMergeResult[i + index].FirstOrDefault(r => r.YNum == currentRowCell.YNum && r.Content == currentRowCell.Content && r.Colspan == currentRowCell.Colspan && r.AllowMerge);
    120                 if (nextRowCell == null)
    121                 {
    122                     break;
    123                 }
    124                 rowspan++;
    125                 currentRowCell = nextRowCell;
    126             }
    127             startRowCell.Rowspan = rowspan;
    128             result.Add(startRowCell);
    129         }
    130     }
    131     return result.Where(r => !(r.Colspan == 1 && r.Rowspan == 1)).ToList();//去除掉不需要合并的单元格
    132 }
    133 
    134 /// <summary>
    135 /// 查询单元格是否被合并了
    136 /// </summary>
    137 /// <param name="mergedCellList">合并的单元格集合</param>
    138 /// <param name="source">要查询的单元格信息</param>
    139 /// <returns></returns>
    140 public static bool IsContainedMergeCell(List<CellInfo> mergedCellList, CellInfo source)
    141 {
    142     CellInfo cell = mergedCellList.FirstOrDefault(r => source.XNum >= r.XNum && source.YNum >= r.YNum && source.XNum < (r.XNum + r.Rowspan) && source.YNum < (r.YNum + r.Colspan));
    143     return cell != null;
    144 }
    View Code

    实体类如下:

     1 //实体类如下:
     2 public class CellInfo
     3 {
     4     /// <summary>
     5     /// 是否启用DrawContent字段
     6     /// </summary>
     7     private bool _UsingDrawContent = false;
     8 
     9     /// <summary>
    10     /// 单元格绘制的内容
    11     /// </summary>
    12     private string _DrawContent;
    13 
    14     /// <summary>
    15     /// X下标
    16     /// </summary>
    17     public int XNum { get; set; }
    18 
    19     /// <summary>
    20     /// Y下标
    21     /// </summary>
    22     public int YNum { get; set; }
    23 
    24     /// <summary>
    25     /// 单元格内容(AllowMerge=true时,判断是否可以合并的依据)
    26     /// </summary>
    27     public string Content { get; set; }
    28 
    29     /// <summary>
    30     /// 单元格绘制内容
    31     /// </summary>
    32     public string DrawContent
    33     {
    34         get
    35         {
    36             if (_UsingDrawContent)
    37             {
    38                 return _DrawContent;
    39             }
    40             return Content;
    41         }
    42         set
    43         {
    44             _DrawContent = value ?? string.Empty;
    45             if (!_DrawContent.Equals(Content))
    46             {
    47                 _UsingDrawContent = true;
    48             }
    49         }
    50     }
    51 
    52     private bool _allowMerge = true;
    53     /// <summary>
    54     /// 是否允许合并
    55     /// </summary>
    56     public bool AllowMerge
    57     {
    58         set
    59         {
    60             _allowMerge = value;
    61         }
    62         get
    63         {
    64             return _allowMerge;
    65         }
    66     }
    67 
    68     private int _rowspan = 1;
    69     /// <summary>
    70     /// 合并的行数
    71     /// </summary>
    72     public int Rowspan
    73     {
    74         set
    75         {
    76             _rowspan = value;
    77         }
    78         get
    79         {
    80             return _rowspan;
    81         }
    82     }
    83 
    84     private int _cowspan = 1;
    85     /// <summary>
    86     /// 合并的列数
    87     /// </summary>
    88     public int Colspan
    89     {
    90         set
    91         {
    92             _cowspan = value;
    93         }
    94         get
    95         {
    96             return _cowspan;
    97         }
    98     }
    99 }
    View Code

    测试代码:

     1 static void Main(string[] args)
     2 {
     3     List<CellInfo> originalData = new List<CellInfo>();
     4 
     5     #region 原始数据
     6     AddCellInfo(originalData, 0, 0, "123", true);
     7     AddCellInfo(originalData, 0, 1, "123", true);
     8     AddCellInfo(originalData, 0, 2, "456", true);
     9     AddCellInfo(originalData, 0, 3, "999", true);
    10     AddCellInfo(originalData, 0, 4, "999", true);
    11     AddCellInfo(originalData, 0, 5, "789", true);
    12     AddCellInfo(originalData, 1, 0, "123", true);
    13     AddCellInfo(originalData, 1, 1, "123", true);
    14     AddCellInfo(originalData, 1, 2, "789", true);
    15     AddCellInfo(originalData, 1, 3, "999", true);
    16     AddCellInfo(originalData, 1, 4, "999", true);
    17     AddCellInfo(originalData, 1, 5, "999", true);
    18     AddCellInfo(originalData, 2, 0, "123", true);
    19     AddCellInfo(originalData, 2, 1, "123", true);
    20     AddCellInfo(originalData, 2, 2, "789", true);
    21     AddCellInfo(originalData, 2, 3, "999", true);
    22     AddCellInfo(originalData, 2, 4, "999", true);
    23     AddCellInfo(originalData, 2, 5, "789", true);
    24     #endregion
    25 
    26     List<CellInfo> mergeCellList = GenerateMergeCellList(originalData);
    27     foreach (CellInfo item in mergeCellList)
    28     {
    29         Console.WriteLine($"({item.XNum},{item.YNum}),clospan:{item.Colspan},rowspan:{item.Rowspan},content:{item.Content}");
    30     }
    31     Console.ReadKey();
    32 }
    33 
    34 private static void AddCellInfo(List<CellInfo> resultList, int xNum, int yNum, string content, bool allowMerge)
    35 {
    36     resultList.Add(new CellInfo()
    37     {
    38         XNum = xNum,
    39         YNum = yNum,
    40         Content = content,
    41         AllowMerge = allowMerge
    42     });
    43 }
    View Code
  • 相关阅读:
    在VS2013创建WebService并在IIS中发布和使用
    Win7下IIS由于扩展配置问题而无法提供请求的页
    webservice 部署后内网不能访问问题
    有关AlterControl控件的简单应用
    部分阉割版Win7无法正常使用TTS语音的解决办法(转载)
    等待资源时检测到死锁
    将php数组转js数组,js如何接收PHP数组,json的用法
    一个炫酷的flash网站模板
    php生成zip压缩文件的方法,支持文件和压缩包路径查找
    谷歌放弃“不作恶” Alphabet要“遵守法律互相尊重”
  • 原文地址:https://www.cnblogs.com/zzgblog/p/14870614.html
Copyright © 2011-2022 走看看