一、實現了上回說到的多功能文本框之後,接下去的任務就是做一個表情符號選擇器。CIconPicker。
說明:本來是想實現圖標選擇的,但是後來有需要改成了位圖選擇器,但是類名沒有改過來,還是叫 CIconPicker。附帶工程中有圖標選擇器。
二、圖標/位圖選擇器(以下簡稱選擇器)的實現原理
當用戶按下選擇器的時候,應該把所有的圖像用一個圖片列表顯示出來;如果用戶選擇了其中一個圖片,則記錄該圖片的編號,並把圖片列表關閉。如果用戶沒有選擇圖片 ,那麼直接把圖片列表關閉 ( 響應 WM_KILLFOCUS 消息 )。
首先,從 CButton 派生一個類 CIconPicker 。給它增加一些成員用來實現"選擇器"的功能。如下所述:
當 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<m_nRow;i++)
{
for(int j=0;j<m_nCol&& i*m_nCol+j<pBitmapArray->GetSize();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);
///設置按鈕的圖標 本文發表於http://bianceng.cn(編程入門網)
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)
只是一個自畫按鈕而已,感應鼠標事件,自畫,貼圖等等都是老生常談了。我就不一一贅述了。若有疑問請看本文附
帶的源代碼。最後的效果如下圖所示:
這樣,一個圖標/圖片選擇器就基本完成了。呵呵,由於水平有限再加上時間倉卒,功能還很不完善,代碼也亂七八糟,大家別用雞蛋砸我,雞蛋用來砸我多可惜啊(要砸也別砸臉,砸我郵箱 :[email protected] :)