一、引言
MSFlexGrid控件是Visual C++中提供的已注册ActiveX控件,它常被用于显示和操作表格式数据,特别是数据库文件的显示及交互操作。在其他程序的交互界面中,对于不确定数目的同类大批量数据的输入而言,MSFlexGrid是十分有效的。利用MSFlexGrid可以将输入文件中的数据显示出来并作交互修改,通过功能扩展可将表格数据直接copy到Excel、Word及Origin中的表格内,利用右键菜单实现此功能。本文编程实现了上述类似功能,并将MSFlexGrid控件的一些调整操作(如行高、列宽、Cell内容的对齐方式等)加以外部按钮化,使其更为方便易用。
二、先行者对MSFlexGrid控件功能的扩充
王勇、李延平[1]提出在MSFlexGrid的当前网格单元(Cell)内创建同样尺寸的编辑框(CEdit)覆盖该Cell,并将Cell内的Text传给编辑框,通过此编辑框以实现MSFlexGrid的网格编辑功能。秦胜[2]提出用信息预解释(PreTranslate)方法,截留编辑框(CEdit)内的ESC键与回车键(Enter)按下消息,以防止在编辑框内不小心按下上述两按键之一时立刻关闭对话框,退出整个程序。李强[3]在此基础上作了一些改进:①对MSFlexGrid控件的Scroll消息响应中,若存在编辑框,则将其销毁。②编辑框内ESC与Enter键消息的PreTranslate,以防止退出整个对话框程序。③使编辑框同MSFlexGrid使用的字体一致。④“高亮度”显示动态创建的编辑框。魏会君[4]用控件聚合技术实现MSFlexGrid控件的Cell编辑与修改功能,并指出可将聚合后的控件编写为一个完整的新的ActiveX控件,以备频繁使用。网上一篇文章[5]在VB中实现了可间隔的多列(multi Columns)选取功能,通过将已“选中”列的颜色设置为正常选中颜色(BackColorSel)来实现之。
三、本文的改进之处
本文除实现上述功能外,另作了如下改进:
(1) 通过在当前网格单元(Current Cell)处创建同样尺寸的编辑框(CEdit)来实现对Cell内容的交互修改,由消息预解释(PreTranslateMessage)拦截编辑框内的ESC与Enter键的按下消息。在Cell内按ESC键时,Cell内的值维持原值不变且EditBox销毁(DestroyWindow),但当前Cell仍具有焦点(focus);再次编辑该Cell时,不能直接生成新的编辑框,可在其附近的Cell中单击后,再单击该Cell即可生成新的编辑框。在Cell内按Enter键时,Cell的值更新为EditBox内的值,同时下一个Cell自动进入编辑状态;其顺序为自动转到同一列的下一行Cell,若已到最大行数处,则转到下一列的起始Cell (FixedColumns不包括在内),若到整个MSFlexGrid的最末一个Cell,则按Enter键时,该Cell处的EditBox销毁但该Cell仍具有焦点,再对该Cell进行编辑的方法同上。
(2) 网格数据自身内部及与外部表格式数据文件间的copy/paste操作功能。将外部表格式数据源(如Excel文件)内的数值直接copy/paste至MSFlexGrid中,可减少输入工作量;有时需将至MSFlexGrid的部分数值输出到Word文件的表格或Origin的DataSheet用于绘图。本文利用系统剪贴板(Clipboard)来传送数值,考虑到MSFlexGrid的行之间的换行符号为“\n”,而Word与Origin中的换行符号为“\n\r”(Excel自动兼容两种格式)。故由MSFlexGrid数值copy至Clipboard时,预先将将其中的“\n”符号替换为“\n\r”,由外部文件paste至MSFlexGrid时作相反的替换。具体操作时,先选中MSFlexGrid内感兴趣的区域(考虑到使用方便,FixedRows/Cols不计在内),在MSFlexGrid外部的主控界面按鼠标右键自动弹出右键菜单,选择Copy或Paste即可。详见源程序中。
(3) MSFlexGrid网格(Cell)属性调整操作的外部按钮化
a. 单元格内的文本对齐方式,选中感兴趣的Cell Range,按“CellAligment”按钮,弹出对齐方式对话框,由水平与垂直方向两个ComboBox组成,选择合适的选项即可。Cell内的对齐方式共有0~9十种,其具体功能见表1.
表1、MSFlexGrid控件的CellAlignment 属性
常数 |
值 |
描述 |
FlexAlignLeftTop |
0 |
单元内容顶部左对齐。 |
FlexAlignLeftCenter |
1 |
单元内容中间左对齐。对字符串的缺省设置值。 |
FlexAlignLeftBottom |
2 |
单元内容底部左对齐。 |
FlexAlignCenterTop |
3 |
单元内容顶部居中。 |
FlexAlignCenterCenter |
4 |
单元内容中间居中。 |
FlexAlignCenterBottom |
5 |
单元内容底部居中。 |
FlexAlignRightTop |
6 |
单元内容顶部右对齐。 |
FlexAlignRightCenter |
7 |
单元内容中间右对齐。对数字的缺省设置值。 |
FlexAlignRightBottom |
8 |
单元内容底部右对齐。 |
FlexAlignGeneral |
9 |
单元内容一般对齐方式。对字符串中间左对齐而对数值中间右对齐。 |
对齐方式对话框的垂直方向ComboV,共有三项可供选择:靠上、居中与靠下;水平方向ComboH,共有四项可供选择:常规、靠左、居中与靠右。其中,“常规”选项相当于值为9的对齐方式(即默认对齐方式),若选择此项则自动将垂直方向ComboV设置为“居中”且ComboV 处于Disabled状态;若选择“常规”此项,程序将ComboH与ComboV的选中状态转换为数值0~8,然后返回此数值。而进入对齐方式对话框时,则根据Cell的当前对齐方式设置ComboH与ComboV的初始选中状态。
b. 修改Title of Fixed Columns
在Fixed Columns处,双击单元格可出现编辑框交互修改Title.同样实现ESC与Enter按键消息的拦截,不过按下上述两键中的任一个时,该单元格(Cell)相应编辑框消失,同时与其紧相邻的正常Cell具有焦点(同正常Cell内用ESC键退出编辑时仅具有焦点一致)。因本程序中Title of Fixed Rows采用行号,由程序自动设置,故不必手工修改。
c. 调整行高、列宽
选中某一行或列,再拖动Splider控件即可调整该行或列的尺寸,同时以ToolTip方式显示行高或列宽的值(本文利用一免费的控件CMFECToolTip[6]来实现此显示功能)。当Splider控件停止拖动操作2秒后,该ToolTip自动消失。可由设置定时(SetTimer)与Splider相应的消息映射(OnReleasedcapture)两种方式来控制ToolTip的消失,本文采用定时法且同时将Splider恢复至中位并将iWidth0/ iHeight0更新为当前相应新值。在Splider拖动过程中,为保持行高或列宽变动的平滑性,作为基数的iWidth0保持不变(Splider的Range为0~20,iWidth0/ iHeight0相当与中位处pos=10,故相应放大/缩小倍数为[0~2])。按下Splider紧下方的“Slider2Center”按钮可将Splider恢复至中位,此时作为基数的iWidth0/ iHeight0亦被更新为当前相应新值iWidth/ iHeight.
d. 行插入/删除
在Fixed Rows处,双击单元格可出现右键菜单,分为删除该行、在该行之前插新行两种情形。新插入行的Cell格式同选中行一致。由于行标同Excel格式一样采用行号,故行插入/删除后,行标自动重新调整。
e. 设置选定区域的颜色
选中感兴趣的Cell Range,按“Color”按钮,弹出颜色设置对话框,选择合适的颜色即可。Cell中的颜色设置用到COLORREF,它是一个32-bit整型数值,代表一种颜色,可使用RGB函数来初始化COLORREF.如将当前Cell的背景色设置为ToolTip中的背景色,用m_gridCtrl.SetCellBackColor(RGB(0xFF,0xFF,0xE1))便可实现。本文给出的颜色设置功能较为简单,至于如何实现MSFlexGrid控件Properties的Color属性页中类似的选择方式,本文仅提供一个解决方案以作参考:可利用VC++中的图像列表功能及取得MSFlexGrid控件Color属性页中相应图块的RGB值,再结合CcolorDialog即可实现之。
本文程序中设置的Cell颜色,在其它相关操作中未作考虑,有可能被重置为正常颜色(即Cell的BackColor为白色,ForeColor为黑色)。
f. 清空选定区域的内容
选中感兴趣的Cell Range,按“ Clear”按钮,可清空选定区域的内容。
g. 实现可间隔多行/列(multi Rows/Columns)的“选中”
通过同时按下“Ctrl”键与Fixed Rows/Columns处的鼠标左键点击(Click)来实现。本文通过全局字符串变量来表征被选中的可间隔的多行/列,对列用“:”+列号组成的字符串strColSel,对行用“;”+行号组成的字符串strRowSel.对不是当前选中行/列的“已选中” 行/列,采用设置其Cell的BackColor与ForeColor分别为BackColorSel与ForeColorSel来实现“选中”效果。Excel中按住“Ctrl”键的同时若先后两次选中同一列,效果同单次选中一样;而Origin中按住“Ctrl”键的同时若先后两次选中同一列,则该列自动从“被选中列组”中消失(即该列恢复至正常颜色),更为实用一些,本文实现了类似Origin中的选取功能。Origin中的上述选取列功能,主要是为了以选中列组为数据源绘制曲线图。除上述多行/列选择的操作之外的操作,将导致“被选中列组”自动消失,且非当前选中列的原“被选中列组”内的列自动恢复至正常色;此时的选择效果同正常状态一致。
本文程序的尚需改进之处:Cell的合并(Merge)功能;当MSFlexGrid下部出现Hscroll时,若第一列数值不在Fixed Rows的紧右边(即Hscroll的滑块不处于最左端时),此时选中某一行,相应Fixed Rows的Cell有可能被正常Cell产生的EditBox遮蔽,从而影响行插入/删除等操作,将Hscroll的滑块拉至最左端即可;被设置为特殊色的Cell,在多行/列选中、行插入/删除、及MSFlexGrid自身内部的Copy/Paste等操作后,仍能保持原特殊色;Cell其他属性(如对齐方式等)的遗传保留;及类似Excel中的格式刷功能等。
四、应用实例
下面为一实用计算程序的输入/输出界面部分,该程序由VC++编制主控程序,调用Matlab完成矩阵运算与计算结果的可视化,并将计算结果传回至主控程序。输入/输出界面利用MSFlexGrid控件以输入大批量的同类数值,并可与外部表格式数据文件间直接作copy/paste操作以减少输入/输出工作量。可由给定的支点数自动确定MSFlexGrid所需行数,手工输入数值,其中最右边一列为计算结果(该列以其他不同的颜色表示)不需输入。MSFlexGrid内的数值,也可由数值文件读入及保存至另外的文件。读入时的数值文件中,以“*”开头的行为注释行(读入时自动跳过该行),每行数值间的分隔符可采用Tab、“,”、空格(space)中的任意一种,不过同一数值文件的行内分隔符应统一,否则出错;最下边的列表框显示数值文件的原内容。保存至另外的文件时,每行数值间以“,”作分隔符,且会提示是否保存最右边一列数值。对话框上的ToMatlab按钮原为形成调用Matlab程序的输入字符串,并调用Matlab计算与显示及取回计算结果,本文程序中将最右边的计算结果一列改为求前面六列相应每行的数值和。程序的运行界面见图2与图3.
五、结束语
本文在先行者对VC++中MSFlexGrid控件功能扩展的基础上,通过“二次开发”进一步扩展了其功能,使其更为方便易用。最后给出了一个具体的应用实例,示例表明本文的程序是实用可靠的,可作为模块应用到其他程序中及形成一完整的新控件。
说明:为简单起见,本文程序仅考虑FixedRows与FixedCols具为1的情形。
本文程序的调试及运行环境为:Windows 98与MSVisual C++6.0 Enterprise Edition
(Copyright_1994-98);屏幕分辨率为1024*768,大字体,125%正常大小(120dpi)。