Spread 之自定义对角线cellType源码: DiagonalCellType
最新的SpreadWinform提供了多达24种CellType类型,下面的这2篇博文对新增了GcTextBoxCellType和GcDateTimeCellType单元格格式做了比较详细的说明。
《Spread 7 for WinForms 新增的GcTextBoxCellType (水印、自动换行、自动大写、长度限制等)》
《Spread 7 for WinForms 新增的GcDateTimeCellType (日期、时间格式)》
一般常规的做法是通过LineShape来做,《Spread for Winforms 表格控件:实现交叉报表》 用LineShape进行了编码实践,使用效果反响不错。
在实际项目中,有人提出,能否自定义一个CellType来实现而不是采用Shape方式呢?
答案是肯定的,下面我们来一一说明详细过程:
在实际项目中有如下三种需求---需要在Spread表头绘制对角线+表头文字:
双区域对角线,定义枚举为:e2Region。
三区域对角线,定义枚举为:e3Region
四区域对角线,定义枚举为:e4Region
Step 1: 输入文字需求
在手绘原型过程中,产生过如下三种原型,在评审中被否决的:
主要是考虑到横线、竖线、斜对角线没有太多的使用场景,目前用不上。
Step 3:DiagonalCellType接口测试开发
自定义CellType的目的是方便使用,故依照TDD的编程思路,先通过接口测试开始第一步工作,方便用户和其他系统自带的CellType切换使用,且能复用Cell已有的BackColor、Font、ForeColor、CellPadding。
下面是双区域对角线的测试使用源码。(实际项目中,仅需要前4行源码即可实现双区域对角线的CellType使用)
1: //Diagonal_2Region
2: DiagonalCellType ct = new DiagonalCellType(DiagonalSubCellType.e2Region);
3: this.fpSpread1.ActiveSheet.Cells[1, 0].CellType = ct;
4: ct.SetText("产品", StringAlignment.Far);
5: ct.SetText("日期", StringAlignment.Near, StringFormatFlags.DirectionVertical);
6: this.fpSpread1.ActiveSheet.Cells[1, 0].BackColor = Color.Green;
7: this.fpSpread1.ActiveSheet.Cells[1, 0].Font = new Font("宋体", 12);
8: this.fpSpread1.ActiveSheet.Cells[1, 0].ForeColor = Color.Blue; //line
9: this.fpSpread1.ActiveSheet.Cells[1, 0].CellPadding = new CellPadding(5);
Step 4:DiagonalCellType设计方法
在双区域、三区域、四区域这3种对角线,彼此之间可复用的代码非常多,故我们考虑了采用如下设计模式:工厂方法、模板方法、策略方法、桥接模式等。
为了简化设计,对DiagonalCellType做了抽象,仅用了24行代码实现了一个对角线的接口类。
1: public class DiagonalCellType : FarPoint.Win.Spread.CellType.TextCellType
2: {
3: #region CTOR
4: SubDiagonalCellTypeBase m_cellType = null;
5: public DiagonalCellType(DiagonalSubCellType subType)
6: {
7: m_cellType = SubDiagonalCellTypeBase.CreateSubType(subType);
8: }
9: #endregion
10:
11: public void SetText(string text, StringAlignment sstringAlignment = StringAlignment.Near, StringFormatFlags ssStringFormatFlags = StringFormatFlags.NoClip)
12: {
13: m_cellType.SetText(text, sstringAlignment, ssStringFormatFlags);
14: }
15:
16: public override void PaintCell(Graphics g, Rectangle r, Appearance appearance, object value, bool isSelected, bool isLocked, float zoomFactor)
17: {
18: m_cellType.PaintCell(g, r, appearance, value, isSelected, isLocked, zoomFactor);
19: }
20:
21: public override System.Windows.Forms.Control GetEditorControl(System.Windows.Forms.Control parent, Appearance appearance, float zoomFactor)
22: {
23: return null;
24: }
25: }
DiagonalCellType继承自TextCellType,为了复用已有的文本单元格属性,而不是“从轮子做起”。这里,我们重载了2个函数,并作了函数覆盖:
PaintCell:GDI+绘制文本、线条核心函数,具体实现3种区域对角线不一样,故在SubDiagonalCellTypeBase类中延迟实现之。
GetEditorControl:考虑到表头区域在绘制表格前已经确定,不需要编辑,故重写函数,返回null则屏蔽了默认的Editor控件。
Step 5: 双区域对角线编码实践
SubDiagonalCellType_2Region是双区域对角线的实现类,共36行代码:
1: public class SubDiagonalCellType_2Region : SubDiagonalCellTypeBase
2: {
3: public override void InnerPaintCell(Graphics g, Rectangle r, Appearance appearance, object value, bool isSelected, bool isLocked, float zoomFactor)
4: {
5: //line 1
6: g.DrawLine(LinePen, r.X, r.Y, r.X + r.Width, r.Y + r.Height);
7:
8: //text 1
9: SizeF sf = m_TextList[0].GetSizeF(g, appearance);
10: float x = r.X + r.Width/2 - sf.Width - appearance.CellPadding.Left;
11: float y = r.Y + appearance.CellPadding.Top;
12: RectangleF rr = new RectangleF(x, y, r.Right - x - appearance.CellPadding.Left, sf.Height);
13: // g.FillRectangle(new SolidBrush(Color.White), rr); //Test Rectangle Size
14: m_TextList[0].DrawString(g, rr, appearance);
15:
16: //text 2
17: sf = m_TextList[1].GetSizeF(g, appearance);
18: y = r.Y + r.Height - sf.Height - appearance.CellPadding.Bottom;
19: x = r.X + appearance.CellPadding.Left;
20: rr = new RectangleF(x, y, r.Width / 2 , sf.Height);
21: // g.FillRectangle(new SolidBrush(Color.White), rr); //Test Rectangle Size
22: m_TextList[1].DrawString(g, rr, appearance);
23: }
24:
25: protected override void ValidateData()
26: {
27: if (m_TextList.Count != 2)
28: {
29: throw new Exception("must SetText twice");
30: }
31: }
32:
33: public override DiagonalSubCellType DiagonalSubCellType
34: {
35: get { return DiagonalSubCellType.e2Region; }
36: }
37: }
- DiagonalSubCellType: 用来标明当前类属于哪种类型
- ValidateData:数据校验,因为双区域需要2个文本,故做判断处理,不满足条件抛出异常。
- InnerPaintCell:实现绘制双区域的函数,这里采用的模板方法,在基类SubDiagonalCellTypeBase已经实现了ValidateData-数据校验、背景色填充等。
- 前景色、背景色、bore、CellPadding复用了Cell自带的,亦可通过Designer设计。
- 为了方便用户使用,添加了编辑器修改对角线文字(文字行不可增减)
GDI+的一些注意事项:
- 垃圾回收完毕后,销毁GDI+对象,这里我们通过微软推荐的using。
- 在使用的Form中,启用buffer和双缓存,代码如下:
1: //提高GDI+ 效率
2: this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
3:
代码如下:
Spread 之自定义对角线cellType源码: DiagonalCellType的更多相关文章
- C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)
C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...
- WPF一步步实现完全无边框自定义Window(附源码)
在我们设计一个软件的时候,有很多时候我们需要按照美工的设计来重新设计整个版面,这当然包括主窗体,因为WPF为我们提供了强大的模板的特性,这就为我们自定义各种空间提供了可能性,这篇博客主要用来介绍如何自 ...
- nGrinder对监控机器收集自定义数据及源码分析
转载:https://blog.csdn.net/neven7/article/details/50782451 0.背景 性能测试工具nGrinder支持在无需修改源码的情况下,对目标服务器收集自定 ...
- Android 自定义相机Demo源码
Github源码:https://github.com/LinJZong/AndroidProject.git 模仿360相机,图片资源来源于360相机,仅供学习使用.使用过程中遇到问题或Bug可发我 ...
- 【转】ANDROID自定义视图——onLayout源码 流程 思路详解
转载(http://blog.csdn.net/a396901990) 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局 ...
- iOS分段选择器、旅行App、标度尺、对对碰小游戏、自定义相册等源码
iOS精选源码 企业级开源项目,模仿艺龙旅行App 标签选择器--LeeTagView CSSegmentedControl常用的分段选择器,简单易用! 仿微信左滑删除 IOS左滑返回 输入框 iOS ...
- 6.2 dubbo在spring中自定义xml标签源码解析
在6.1 如何在spring中自定义xml标签中我们看到了在spring中自定义xml标签的方式.dubbo也是这样来实现的. 一 META_INF/dubbo.xsd 比较长,只列出<dubb ...
- HTML5视频(自定义视频播放器源码)
video对象 兼容情况: safari浏览器不支持webm格式 Chrome浏览器支持webm格式 ie8以及以下不支持video标签 , ie9支持video标签 ,但是支持mp4格式的 Fire ...
- 【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量—— ...
随机推荐
- hdoj 1106 排序
排序 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...
- android http 通信(java原生类库实现)
get方式 private void doGet(){ URL httpurl = new URl(url); HttpURLConnection conn = (HttpURLConnection) ...
- 利用接口做参数,写个计算器,能完成+-*/运算 (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) 此方法要求能够:1.用传递过来的对象调用compute
package com.homework5; public interface Compute { //声明抽象方法 int computer(int n,int m); } package com. ...
- MySQL中UNION和UNION ALL的使用
在数据库中,UNION和UNION ALL关键字都是将两个结果集合并为一个,但这两者从使用和效率上来说都有所不同. MySQL中的UNION UNION在进行表链接后会筛选掉重复的记录,所以在表链接后 ...
- 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)
一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...
- 判断数组(array)中是否包含某个字符(contains)
$a="a","","b" $a -contains "a" 返回 $true $a -notcontains &quo ...
- 将string转换成UTF8在进行请求
在请求服务器时,如果参数中带有中文字符.就会报参数格式错误,需要将其转换成UTF8 @interface NSString (NSURLUtilities) /* Adds all percent e ...
- C# 创建、安装和卸载Windows服务程序
1.新建一个windows服务程序. 2.点击这个服务类,从工具箱中加入一个Timer控件,右键这个Timer控件 命名为 timerOrderDeductionDetailJob,Enable设为T ...
- 征服 Nginx + Tomcat
2年前一直折腾Apache,现如今更习惯Nginx. 搭建网站又遇到2年前遇到的问题——Session同步. (参考我以前的帖子——征服 Apache + Tomcat)只不过现今担当负载均衡的Apa ...
- java推断字符串是否为乱码
项目中有一个功能 在IE中GET方式提交会产生乱码 但有两个入口都会走这同一段代码 固不能直接转码,所以要进行推断传过来的该值是不是乱码 可用下面方式验证: java.nio.charset.Char ...