类似 MSN 信息发送框的制作(下)

类似 MSN 带转义字符的信息发送框的制作()


作者:阙荣文 (querw)


asp?id=2318">
下载源代码

一、实现了上回说到的多功能文本框之后,接下去的任务就是做一个表情符号选择器。CIconPicker

说明:本来是想实现图标选择的,但是后来有需要改成了位图选择器,但是类名没有改过来,还是叫 CIconPicker。附带工程中有图标选择器。

二、图标/位图选择器(以下简称选择器)的实现原理

  当用户按下选择器的时候,应该把所有的图像用一个图片列表显示出来;如果用户选择了其中一个图片,则记录该图片的编号,并把图片列表关闭。如果用户没有选择图片 ,那么直接把图片列表关闭 ( 响应 WM_KILLFOCUS 消息 )
  首先,从 CButton 派生一个类 CIconPicker 。给它增加一些成员用来实现"选择器"的功能。如下所述:

·  1、图片列表:CArray 存放所有下拉图片,每个图片都有一个编号,即它在图片数组中的序号

·  2GetBitmapAt():顾名思义,按序号获取图片

·  3AddBitmap():添加一张图片

·  4GetCurrentBitmapIndex():返回选中图片的序号

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;
         ptx=rectleft;pty=rectbottom;
         
         //创建一个图片列表容器
         m_pIconContainer=new CIconContainer;
         
         ///把图片数组当作参数传过去
         if(m_pIconContainer->Create(ptthis&m_BitmapArray))
         {
                 m_pIconContainer->ShowWindow(SW_SHOW);
                 m_pIconContainer->UpdateWindow();
                 m_pIconContainer->SetFocus();
         }
}

2、为每一张图片在容器内创建一个按钮CInnerButton。我把这个工作交给容器来完成。重载容器(CIconContainer)Create()函数,如下:

BOOL CIconContainer::Create(POINT ptCButton* pParentButtonCArray *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=bmbmWidth+4;      //内部单元的宽度
         m_nCellHeight=bmbmHeight+4;     //内部单元的高度
         
         CRect rect;
         rectleft=ptxrecttop=pty;
         rectright=ptx+m_nCellWidth*m_nCol;   //容器的宽度
         
         if(pBitmapArray->GetSize()%m_nCol==0)   //计算行数
         {
                 m_nRow=pBitmapArray->GetSize()/m_nCol;
         }
         else
         {
                 m_nRow=pBitmapArray->GetSize()/m_nCol+1;
         }
         rectbottom=pty+m_nCellHeight*m_nRow+2+46;  ///容器的高度=(行数+2)*单元宽度
         
         //pParentButton->GetParent()->ScreenToClient(&rect);
         
         ///创建容器
         //CWnd::Create(NULL NULL WS_VISIBLE | WS_CHILD
         //rectpParentButton->GetParent()IDC_ICONCONTAINER NULL);

 

         CWnd::CreateEx(WS_EX_LEFTAfxRegisterWndClass(0)NULLWS_VISIBLE|WS_POPUPrectNULLNULL );

 

         ///创建图片张数+2个按钮
         for(int i=0;i<m_nRow;i++)
         {
                 for(int j=0;j<m_nCol&& i*m_nCol+j<pBitmapArray->GetSize();j++)
                 {
                          ///计算按钮的位置
                          CRect innerrect;
                          innerrectleft=j*m_nCellWidth;
                          innerrecttop=i*m_nCellHeight;
                          innerrectright=innerrectleft+m_nCellWidth;
                          innerrectbottom=innerrecttop+m_nCellHeight;
                          
                          innerrectDeflateRect(22);
                          
                          ///新建按钮
                          CInnerButton *pInnerButton;
                          pInnerButton=new CInnerButton;
                          pInnerButton->Create(NULLWS_CHILD |WS_VISIBLE
                                   innerrectthisIDC_INNERBUTTON+i*m_nCol+j);
                          
                          ///设置按钮的图标
                          pInnerButton->SetBitmap(pBitmapArray->GetAt(i*m_nCol+j));
                          pInnerButton->ShowWindow(SW_SHOW);
                          
                          ///记录该按钮的指针
                          m_InnerButtonArrayAdd(pInnerButton);
                 }
         }
         
         
         ////创建两个扩展功能按钮
         this->GetClientRect(&rect);
         CInnerButton *pInnerButton;
         pInnerButton=new CInnerButton;
         
         rectleft=2;
         rectright-=2;
         recttop=m_nRow*m_nCellHeight+3;
         rectbottom=recttop+20;  //按钮的高度为22
         
         
         pInnerButton->Create(NULLWS_CHILD |WS_VISIBLE
                 rectthisIDC_INNERBUTTON-1);
         pInnerButton->SetFont(m_pParentButton->GetParent()->GetFont());
         pInnerButton->SetWindowText("显示更多的图释");
         
         pInnerButton=new CInnerButton;
         
         recttop=rectbottom+3;
         rectbottom=recttop+20;
         pInnerButton->Create(NULLWS_CHILD |WS_VISIBLE
                 rectthisIDC_INNERBUTTON-2);
         pInnerButton->SetWindowText("我的自定义图释");
         pInnerButton->SetFont(m_pParentButton->GetParent()->GetFont());
         
         return TRUE;
}

  当用户单击了其中的一个按钮时,把序号记录下来(可以根据InnerButtonID,创建的时候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(SelectFileDlgDoModal()==IDOK)
                 {
                          ((CIconPicker*)m_pParentButton)->AddBitmap(SelectFileDlgGetPathName());
                 }
         }
         ///关闭本窗口
         Close(LOWORD(wParam)-IDC_INNERBUTTON); ///在这里根据ID取得序号
         ///消息发送的语句在Close()
         return TRUE;
}

这样容器的任务就完成了。如何显示图片那是内部按钮(CInnerButton)的事。

3
、实现内部按钮(CInnerButton)
  只是一个自画按钮而已,感应鼠标事件,自画,贴图等等都是老生常谈了。我就不一一赘述了。若有疑问请看本文附
带的源代码。最后的效果如下图所示:



  这样,一个图标/图片选择器就基本完成了。呵呵,由于水平有限再加上时间仓卒,功能还很不完善,代码也乱七八糟,大家别用鸡蛋砸我,鸡蛋用来砸我多可惜啊(要砸也别砸脸,砸我邮箱 [email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章