MS Flex Grid控件.docx
《MS Flex Grid控件.docx》由会员分享,可在线阅读,更多相关《MS Flex Grid控件.docx(11页珍藏版)》请在冰豆网上搜索。
MSFlexGrid控件
MSFlexGrid控件是微软的一个网格控件,可以用于显示数据库中的信息,对于
一些比较简单的显示方式,还是比较方便的。
加入MSFlexGrid控件控件的方法:
在VC中选择Project|AddtoProject|ConpenmentsandControls在弹出的对话框中
选择RegisteredActiveXControls然后选择MicrosoftFlexGridControl,version6.0。
系统会提示你加入几个类进入你的工程。
包括四个类:
CMSFlexGrid,CRowCursor,COleFont,CPicture;
同时在VC的Control面板上会显示出MSFlexGrid控件的图标,可以同其他普通
控件一样操作这个控件。
一、引言
MSFlexGrid控件是VisualC++中提供的已注册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中实现了可间隔的多列(multiColumns)选取功能,通过将已“选中”列的颜色设置为正常选中颜色(BackColorSel)来实现之。
三、本文的改进之处
本文除实现上述功能外,另作了如下改进:
(1)通过在当前网格单元(CurrentCell)处创建同样尺寸的编辑框(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.单元格内的文本对齐方式,选中感兴趣的CellRange,按“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.修改TitleofFixedColumns
在FixedColumns处,双击单元格可出现编辑框交互修改Title.同样实现ESC与Enter按键消息的拦截,不过按下上述两键中的任一个时,该单元格(Cell)相应编辑框消失,同时与其紧相邻的正常Cell具有焦点(同正常Cell内用ESC键退出编辑时仅具有焦点一致)。
因本程序中TitleofFixedRows采用行号,由程序自动设置,故不必手工修改。
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.行插入/删除
在FixedRows处,双击单元格可出现右键菜单,分为删除该行、在该行之前插新行两种情形。
新插入行的Cell格式同选中行一致。
由于行标同Excel格式一样采用行号,故行插入/删除后,行标自动重新调整。
e.设置选定区域的颜色
选中感兴趣的CellRange,按“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.清空选定区域的内容
选中感兴趣的CellRange,按“Clear”按钮,可清空选定区域的内容。
g.实现可间隔多行/列(multiRows/Columns)的“选中”
通过同时按下“Ctrl”键与FixedRows/Columns处的鼠标左键点击(Click)来实现。
本文通过全局字符串变量来表征被选中的可间隔的多行/列,对列用“:
”+列号组成的字符串strColSel,对行用“;”+行号组成的字符串strRowSel.对不是当前选中行/列的“已选中”行/列,采用设置其Cell的BackColor与ForeColor分别为BackColorSel与ForeColorSel来实现“选中”效果。
Excel中按住“Ctrl”键的同时若先后两次选中同一列,效果同单次选中一样;而Origin中按住“Ctrl”键的同时若先后两次选中同一列,则该列自动从“被选中列组”中消失(即该列恢复至正常颜色),更为实用一些,本文实现了类似Origin中的选取功能。
Origin中的上述选取列功能,主要是为了以选中列组为数据源绘制曲线图。
除上述多行/列选择的操作之外的操作,将导致“被选中列组”自动消失,且非当前选中列的原“被选中列组”内的列自动恢复至正常色;此时的选择效果同正常状态一致。
本文程序的尚需改进之处:
Cell的合并(Merge)功能;当MSFlexGrid下部出现Hscroll时,若第一列数值不在FixedRows的紧右边(即Hscroll的滑块不处于最左端时),此时选中某一行,相应FixedRows的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的情形。
本文程序的调试及运行环境为:
Windows98与MSVisualC++6.0EnterpriseEdition
VC6.0中基于MSFlexGrid的可编辑表格的制作及其若干问题的解决方案
2009-11-1610:
32
一、概述
在我们制作的用户界面中很多时候会用到表格,当然我们首先想到的是用控件,如MSFlexGrid。
我们可以方便的调用控件自身的函数来对表格中的元素进行操作,但是如果要设计一个可以编辑的表格,我们该怎么办呢?
事实上这种可编辑表格的应用还真的不少,主要是其用户操作的交互性较好。
笔者在前一阶段开发项目时遇到了这个问题,以下介绍笔者的实现方案。
二、可编辑表格的初步实现
1、创建新类CCtrlEditGrid
首先创建一个单文档工程EditGrid。
接着在工程中加入MSFlexGrid控件。
这是个ActiveX控件,选择AddToProject的ComponentsandControlsGallery选项可加入该控件。
然后以MSFlexGrid为基类创建新类CCtrlEditGrid,并添加成员函数voidInitGrid()(该函数目前只是空的)和成员变量CEdit*m_pEdit;
CSpinButtonCtrl*m_pSpinButtonCtrl;以后表格的实体类就是该类。
2、在工程文件的视图类中显示表格
首先在视图类CEditGridView中添加成员变量CCtrlEditGrid*m_pCtrlEditGrid。
接着添加CEditGridView的消息相应函数OnCreate,在其中创建表格
m_pCtrlEditGrid=newCCtrlEditGrid;
m_pCtrlEditGrid->Create(NULL,WS_CHILD|WS_VISIBLE,CRect(0,0,0,0),this,ID_EDITGRID);
m_pCtrlEditGrid->InitGrid();
然后为了和视图的大小保持一致在CEditGridView的消息相应函数OnSize中添加代码
if(m_pCtrlEditGrid!
=NULL)
m_pCtrlEditGrid->MoveWindow(0,0,cx,cy);
3、实现CCtrlEditGrid的InitGrid的函数
InitGrid完成表格的属性设置,表格初始内容的填写,可编辑控件的创建。
这里的可编辑控件如CEdit,CComboBox,CSpinButtonCtrl,CDateTimeCtrl……。
在本例中只使用CEdit和CSinButtonCtrl的结合这一种。
如果表格中不同列之间的编辑控件不同,在程序中可以通过检测列号,来决定使用什么控件,事实上在笔者的项目中不同列之间也是使用不同编辑控件的。
在此用一种控件来说明表格编辑的实现方法,读者想换其他的控件也很容易了。
voidCCtrlEditGrid:
:
InitGrid()
{
//设置行数,列数
SetCols(COL_INITNUMBER);
SetRows(ROW_INITNUMBER);
//设置为无边框
SetBorderStyle(0);
//设置为可以改变行高列宽
SetAllowUserResizing(3);
//设置行宽列宽
CDC*pDC=GetDC();
SetRowHeightMin((long)(ROW_HEIGHT_PIXEL*1440.0/pDC->GetDeviceCaps(LOGPIXELSY)));//坐标单位要转换
for(inti=0;i SetColWidth(i,(long)(COL_WIDTH_INDEX_PIXEL*1440.0/pDC->GetDeviceCaps(LOGPIXELSX)));
ReleaseDC(pDC);
//设置列的文字对齐方式
for(i=0;i SetColAlignment(i,4);
//设置固定行列的名称
for(i=1;i {
CStringstrNum;
intnNum=i;
strNum.Format("%d",i);
SetTextMatrix(i,0,strNum);
}
for(i=1;i {
CStringstrNum;
intnNum=i;
strNum.Format("%d",i);
SetTextMatrix(0,i,strNum);
}
//填充Grid中的原始内容
for(i=1;i {
for(intj=1;j {
SetTextMatrix(i,j,"1");
}
}
//创建控件
m_pEdit=newCEdit();
m_pEdit->Create(WS_CHILD|WS_BORDER|ES_AUTOHSCROLL|ES_NUMBER,CRect(0,0,0,0),this,ID_CTRL_EDIT);
m_pSpinButtonCtrl=newCSpinButtonCtrl();
m_pSpinButtonCtrl->Create(UDS_ARROWKEYS|UDS_SETBUDDYINT|UDS_ALIGNRIGHT|WS_BORDER,
CRect(0,0,0,0),this,ID_CTRL_SPIN);
这里要解释说明的是MSFLEXGRID中的单位是缇(1缇=1/1440in),所以在我们要指定单元格的长宽等时,要将像素单位转换为缇。
如ROW_HEIGHT_PIXEL*1440.0/pDC->GetDeviceCaps(LOGPIXELSY)。
其中ROW_HEIGHT_PIXEL是一个表示行高的像素单位的宏,pDC->GetDeviceCaps(LOGPIXELSY)得到Y轴每inch的像素值。
该式计算后的值就是相应的以缇为单位的值。
4、让表格可以编辑
以上三点只是准备阶段,要想使表格编辑,我们还要响应用户的点击单元格事件和离开单元格事件,以使得当用户点击某一单元格时当前单元格处于编辑状态而离开时又处于非编辑状态。
MSFLEXGRID控件提供的OnClick和OnLeaveCell事件正好是我们所需要的。
由于CCtrlEditGrid不是MFC类,所以不能用类向导来添加事件。
只好用手工添加了。
首先在头文件中添加afx_msgvoidOnLeaveCell();afx_msgvoidOnClick();接着在CPP文件中添加事件映射表
BEGIN_EVENTSINK_MAP(CCtrlEditGrid,CMSFlexGrid)
//{{AFX_EVENTSINK_MAP(CEditGrid)
ON_EVENT_REFLECT(CCtrlEditGrid,72/*LeaveCell*/,OnLeaveCell,VTS_NONE)
ON_EVENT_REFLECT(CCtrlEditGrid,-600/*Click*/,OnClick,VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
(如果用户觉得手工添加时间映射表有困难,可以先在应用程序中添加一个虚设对话框。
接着在对话框中插入MSFlexGrid控件。
然后使用ClassWizard将事件处理程序写入对话框,接下来就可以参照着对话框编写事件映射表了。
记得最后要删除虚设对话框。
)
接着添加OnLeaveCell和OnClick的函数体。
OnLeaveCell函数:
如果现在m_pEdit是显示的,则说明单元格是在编辑状态,所以要将数据从m_pEdit框读到表格中,然后将m_pEdit和m_pSpinButtonCtrl隐藏。
voidCCtrlEditGrid:
:
OnLeaveCell()
{
if(m_pEdit->IsWindowVisible())
{