关于CComboBox的自绘

来源:互联网 发布:淘宝网管家 编辑:程序博客网 时间:2024/06/02 18:16

我想,如果大家学过一些控件的自绘的话,CComboBox算是很难的一种了.首先是它本身的复杂度:它由三个控件组成(CEdit,CListBox,CButton).我想但就CEdit来讲,就够你受得了.还要想想他们之间的消息传递....不禁让人无从下手.

当然,如果想要让我自己来完全自绘控件的话,我告诉你,我确实也办不到.我想我还没有能力做这样的事情.但是对于CComboBox如果想要一些简单的效果的话,没有必要花费那么大的力气来完全重绘.我们可以利用他本身的一些属性就可以了.我这里说的都是从CComboBox直接继承下来的.

好了,废话说了一大堆.现在就开始CComboBox的自绘吧.

首先我们可以看看它的一些属性.首先最容易不理解的是Data属性(这个在VC++6.0里面在属性选项卡里面的数据列表里.但是在VS2003以上,都有一个单独的属性data).首先我们可以从这里开始.我们建立一个对话框MFC程序,拖上一个CComboBox空间,在data属性(编译器对应)里面输入数据,观察效果.很容易发现它就相当于AddString函数.当然你的程序可能不止一个选项,我们可以用Ctrl+Enter或者分号来连接下一个选项(其分别对应VC++6.0和VS2003).看看效果.声明一下,以下讨论的内容很少涉及到VC++6.0编译器.究其原因,主要是编译器的bug太多了,搞得人受不了.

我们在看看其他的几个选项.

Owner Draw属性:这个属性有三个选项:No(不解释),Fixed(固定属性的列表高度和宽度),Variable(改变列表的高度和宽度).最直白的理解分别是:不响应DrawItem(这个都不响应其他的自绘消息免谈了)、响应DrawItem(不响应MeasureItem)、响应MeasureItem(当然也响应DrawItem).从这里我们可以看到他们是一级一级的深入的.

还需要提到的是Sort属性,就是排列属性,这个属性就是为是否自动排序准备的,如果你要选择他,就得要响应CompareItem消息,然而由于我这次并没有用到他,所以暂且跳过吧.

还有一个比较重要的是Type属性:Simple(简单的,也就是相当于CEdit)、Dropdown(相当于前面说的三个控件)和DropList(可以理解成是只读的CEdit+CButton+CListBox).其中,我要说的其实就是第三种.因为第一种没的讲,第二种有太难.第三种刚刚好.

好,现在我们开始自绘.

自绘这个控件最大的几个难点是:

1. 数据的传递

2. 消息的处理.(主要是OnPaint和DrawItem).

第一个难点我们可以通过一个成员变量解决,我们先定义一个结构体:

//结构

typedef struct  tagITEMLIST

{

HICON hIcon; //图标

CString strUrl; //Url地址

CString strTitle; //标题(Url官网名称)

COLORREF clrLeft; //左边文本的颜色

COLORREF clrRight; //右边文本的颜色

}ItemList,*PItemList;

这个结构体就是用来保存从主界面传给控件的数据的.

我们可以定义一个这样的vector,方便扩充数据.接着我们按如下插入数据:

ItemList* pItem = new ItemList;

pItem->clrLeft = RGB( 0,132,114 );

pItem->clrRight = RGB( 0,255,125 );

pItem->hIcon = AfxGetApp()->LoadIcon( IDI_ICON1 );

pItem->strTitle = _T("腾讯首页");

pItem->strUrl = _T( "http://www.qq.com" );

AddString( _T("腾讯首页") );

m_vecItemList.push_back( pItem );

如果我不AddString,那么数据就加不进去.我想最大的原因应该是它内部实际上就是这个时候填充一些数据(或初始化)到这个控件上的.当然这只是猜测.具体如何我也不晓得.

这样的话,我们就完成了数据的传递,以后我们可以利用lpDrawItemStruct里面的itemID来获取其用AddString的ID号.通过这个ID号,我们可以获取到整个ItemList的结构.从而绘制相应的东西.

第二个难点我们可以使用探测法来看到底怎样触发这两个消息.

分别在DrawItem上和OnPaint上打一个断点.看什么时候进DrawItem什么时候进OnPaint.

经过这样的分析我们可以知道,当单击了按钮,显示下拉的时候,它才进DrawItem.当需要刷新非下拉区域时进入OnPaint.

两个消息分清楚之后,所有问题都迎刃而解了.

剩下的就是选中下列列表项时应该做什么操作的问题.在列表项被选中的时候,我们刷新下界面就完全搞定了./

还有一点就是下拉列表项的高度和大小的设置,这正是MeasureItem所要做的.

整个自绘过程其实也并不复杂.需要工程文件的可以留言.

原创粉丝点击