扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
一、实现了上回说到的多功能文本框之后,接下去的任务就是做一个表情符号选择器。CIconPicker。
说明:本来是想实现图标选择的,但是后来有需要改成了位图选择器,但是类名没有改过来,还是叫 CIconPicker。附带工程中有图标选择器。
二、图标/位图选择器(以下简称选择器)的实现原理
当用户按下选择器的时候,应该把所有的图像用一个图片列表显示出来;如果用户选择了其中一个图片,则记录该图片的编号,并把图片列表关闭。如果用户没有选择图片 ,那么直接把图片列表关闭 ( 响应 WM_KILLFOCUS 消息 )。
首先,从 CButton 派生一个类 CIconPicker 。给它增加一些成员用来实现"选择器"的功能。如下所述:
1、图片列表:CArray 存放所有下拉图片,每个图片都有一个编号,即它在图片数组中的序号
2、GetBitmapAt():顾名思义,按序号获取图片
3、AddBitmap():添加一张图片
4、GetCurrentBitmapIndex():返回选中图片的序号
当 CIconPicker 收到 WM_LBUTTONDOWN 消息时先不忙给父窗体发送 WM_COMMAND消息 ,而是创建一个图片列表CIconContainer(容器),然后在容器上面创建和图片数量一样多的按钮,每个按钮显示一张图片。当然,为了
实现这个功能还得从CButton再派生一个类CInnerButton用来显示图片,感应鼠标事件。
三、源代码说明
1、创建容器
void CIconPicker::OnLButtonDown(UINT nFlags, CPoint point)
{
if(m_bState) return ;
m_bState=TRUE;
this->SetState(TRUE);
RECT rect;
this->GetWindowRect(&rect);
POINT pt;
pt。x=rect。left;pt。y=rect。bottom;
//创建一个图片列表容器
m_pIconContainer=new CIconContainer;
///把图片数组当作参数传过去
if(m_pIconContainer->Create(pt,this,&m_BitmapArray))
{
m_pIconContainer->ShowWindow(SW_SHOW);
m_pIconContainer->UpdateWindow();
m_pIconContainer->SetFocus();
}
}
2、为每一张图片在容器内创建一个按钮CInnerButton。我把这个工作交给容器来完成。重载容器(CIconContainer)的Create()函数,如下:
BOOL CIconContainer::Create(POINT pt,CButton* pParentButton,CArray *pBitmapArray)
{
if(pBitmapArray->GetSize()<=0)return FALSE;
m_pParentButton=pParentButton;
///根据每张图片的大小创建IconContainer
m_nCol=int(sqrt(pBitmapArray->GetSize()))+1; //计算列数
BITMAP bm;
pBitmapArray->GetAt(0)->GetBitmap(&bm); //以图片列表中的第0号图片的大小为
基准
m_nCellWidth=bm。bmWidth+4; //内部单元的宽度
m_nCellHeight=bm。bmHeight+4; //内部单元的高度
CRect rect;
rect。left=pt。x,rect。top=pt。y;
rect。right=pt。x+m_nCellWidth*m_nCol; //容器的宽度
if(pBitmapArray->GetSize()%m_nCol==0) //计算行数
{
m_nRow=pBitmapArray->GetSize()/m_nCol;
}
else
{
m_nRow=pBitmapArray->GetSize()/m_nCol+1;
}
rect。bottom=pt。y+m_nCellHeight*m_nRow+2+46; ///容器的高度=(行数+2)*单元宽度
//pParentButton->GetParent()->ScreenToClient(&rect);
///创建容器
//CWnd::Create(NULL, NULL, WS_VISIBLE | WS_CHILD,
//rect,pParentButton->GetParent(),IDC_ICONCONTAINER, NULL);
CWnd::CreateEx(WS_EX_LEFT,AfxRegisterWndClass(0),NULL,WS_VISIBLE|WS_POPUP,rect,NULL,NULL );
///创建图片张数+2个按钮
for(int i=0;i { for(int j=0;j { ///计算按钮的位置 CRect innerrect; innerrect。left=j*m_nCellWidth; innerrect。top=i*m_nCellHeight; innerrect。right=innerrect。left+m_nCellWidth; innerrect。bottom=innerrect。top+m_nCellHeight; innerrect。DeflateRect(2,2); ///新建按钮 CInnerButton *pInnerButton; pInnerButton=new CInnerButton; pInnerButton->Create(NULL,WS_CHILD |WS_VISIBLE, innerrect,this,IDC_INNERBUTTON+i*m_nCol+j); ///设置按钮的图标 pInnerButton->SetBitmap(pBitmapArray->GetAt(i*m_nCol+j)); pInnerButton->ShowWindow(SW_SHOW); ///记录该按钮的指针 m_InnerButtonArray。Add(pInnerButton); } } ////创建两个扩展功能按钮 this->GetClientRect(&rect); CInnerButton *pInnerButton; pInnerButton=new CInnerButton; rect。left=2; rect。right-=2; rect。top=m_nRow*m_nCellHeight+3; rect。bottom=rect。top+20; //按钮的高度为22 pInnerButton->Create(NULL,WS_CHILD |WS_VISIBLE, rect,this,IDC_INNERBUTTON-1); pInnerButton->SetFont(m_pParentButton->GetParent()->GetFont()); pInnerButton->SetWindowText("显示更多的图释"); pInnerButton=new CInnerButton; rect。top=rect。bottom+3; rect。bottom=rect。top+20; pInnerButton->Create(NULL,WS_CHILD |WS_VISIBLE, rect,this,IDC_INNERBUTTON-2); pInnerButton->SetWindowText("我的自定义图释"); pInnerButton->SetFont(m_pParentButton->GetParent()->GetFont()); return TRUE; } 当用户单击了其中的一个按钮时,把序号记录下来(可以根据InnerButton的ID,创建的时候ID是递增的)并给父窗体(CIconPicker)发送一个消息,把序号送过去。 BOOL CIconContainer::OnCommand(WPARAM wParam, LPARAM lParam) { if(LOWORD(wParam)-IDC_INNERBUTTON==-1) { ////在这里响应"显示更多的图释" } if(LOWORD(wParam)-IDC_INNERBUTTON==-2) { ////在这里响应"我的自定义图释" CFileDialog SelectFileDlg(TRUE,"bmp","noname",OFN_FILEMUSTEXIST, "Bitmap File(*。bmp)|*。bmp",m_pParentButton); if(SelectFileDlg。DoModal()==IDOK) { ((CIconPicker*)m_pParentButton)->AddBitmap(SelectFileDlg。GetPathName()); } } ///关闭本窗口 Close(LOWORD(wParam)-IDC_INNERBUTTON); ///在这里根据ID取得序号 ///消息发送的语句在Close()中 return TRUE; } 这样容器的任务就完成了。如何显示图片那是内部按钮(CInnerButton)的事。 3、实现内部按钮(CInnerButton) 只是一个自画按钮而已,感应鼠标事件,自画,贴图等等都是老生常谈了。我就不一一赘述了。若有疑问请看本文附 带的源代码。最后的效果如下图所示: 这样,一个图标/图片选择器就基本完成了。呵呵,由于水平有限再加上时间仓卒,功能还很不完善,代码也乱七八糟,大家别用鸡蛋砸我,鸡蛋用来砸我多可惜啊(要砸也别砸脸,砸我邮箱 :querw@sina.com :)
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者