自定义一个combobox,主要完成的功能是换肤。
一开始想到的是重载combobox,然后在combobox原有的基础上修修改改。但是我没找到在我有限的知识上完成的好方法。
combobox也就是组合框嘛,所以我就用几个控件组合在一起咯。当然我不会把所有的功能都去实现。
combobox分别由static、dialog、listbox组成。当然可以用edit、button、static、listbox、dialog,因为是完成任务嘛,所以就没弄那么复杂了。
1、自定义一个static,实现动态切换图片功能,左击弹出对话框,提供函数接口。
2、自定义一个dialog,这个dialog组要是作为listbox的容器。细心的人应该会发现comobox的下拉框是总是置顶的,所以就想到对话框了。
3、自定义一个listbox,这里是整个的关键地方。listbox可以更改背景色和前景色,但是自带的滚动条是没有提供属性接口去改,这个我之前写minigui这个控件
时,是自己去写一个的。性能很不好。所以我这次用了别人的类。
如图:
具体实现:
(1) listbox背景色和前景色
我是在OnEraseBkgnd函数里写代码,为客户区域填充颜色。当然方法很多,网上搜搜就有。
代码如下:
BOOL CMyListBox::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(pDC){
CRect rt;
GetClientRect(&rt);
pDC-> FillRect(&rt,&CBrush(RGB(200,200,200)));
}
return TRUE;
//return CListBox::OnEraseBkgnd(pDC);
}
(2)修改item选中项的颜色和字体颜色
void CMyListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
int nCount = GetCount();
if (nCount == 0)
{
return;
}
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
COLORREF clrItemText;
switch ( lpDrawItemStruct->itemAction )
{
case ODA_SELECT:
case ODA_DRAWENTIRE:
case ODA_FOCUS:
if ( lpDrawItemStruct->itemState & ODS_SELECTED )
{
HBRUSH hbrush = CreateSolidBrush(RGB(0,190,255));//创建一个画刷
clrItemText = GetSysColor(COLOR_WINDOWTEXT);
FillRect( lpDrawItemStruct->hDC,&lpDrawItemStruct->rcItem,hbrush);
SetTextColor(lpDrawItemStruct->hDC,RGB(255,255,0));
DeleteObject(hbrush);
}
else
{
clrItemText = GetSysColor( COLOR_WINDOWTEXT );
pDC->FillSolidRect(&lpDrawItemStruct->rcItem,RGB(200,200,200));
SetTextColor(lpDrawItemStruct->hDC,clrItemText);
}
}
CRect rectFull = lpDrawItemStruct->rcItem;
CString Text;
CString strItem((LPCTSTR)lpDrawItemStruct->itemData);
CString text;
GetText(lpDrawItemStruct->itemID, text);
UINT nIndex = lpDrawItemStruct->itemID;
GetText(nIndex,Text);
pDC->SetBkMode(TRANSPARENT);
pDC->TextOut(rectFull.left+5,rectFull.top+2,text);
// TODO: 添加您的代码以绘制指定项
}
(3)如何让item的光标跟随鼠标移动,因为listbox本身没有这个功能。所以要自己去实现。
在OnMouseMove事件里,for循环判断鼠标在哪个item的区域里。
代码:
void CMyListBox::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
int nCount = GetCount();
for (int i = 0; i <nCount; i++)
{
RECT rc;
this->GetItemRect(i,&rc);
if(rc.top<point.y&&rc.bottom>point.y&&rc.left<point.x&&rc.right>point.x)
{
SetCurSel(i);
break;
}
}
CListBox::OnMouseMove(nFlags, point);
}
(4)当listbox失去焦点的时候隐藏,比如我们点击listbox之外的区域,listbox自动隐藏。
开始的时候我想到的是killfocus事件,后来发觉我没成功。因为listbox本身就有很多控件,用killfocus会出乱子。
所以我就使用了OnActivate这个函数,当然这个是在listbox的容器dialog上的。OnActivate是窗口每次激活时的事件,激活也就是当前活动啦。
因为之前比较少用到这个事件,所以解释一下。
代码:
void CComboboxListboxDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
CDialogEx::OnActivate(nState, pWndOther, bMinimized);
if (WA_INACTIVE == nState)
{
this->ShowWindow(SW_HIDE);
}
// TODO: 在此处添加消息处理程序代码
}
(5)滚动条换肤,因为我是用别人的类,所以就没话说了。
这个是刚调到window组,老大给我的任务。自己记录一下。。。
具体项目源码: