類似 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]

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