唐夏華
(廣西華藍設計(集團)有限公司,廣西 南寧 530001)
MFCGrid控件ButtonCell功能的實現(xiàn)
唐夏華
(廣西華藍設計(集團)有限公司,廣西 南寧 530001)
MFCGrid提供的單元格式類型雖然比較豐富,但是其缺少了一個常用的單元格類型:按鈕型,即在單元格上有一個按鈕,點擊時可以出現(xiàn)界面供用戶選擇數(shù)據(jù),用戶也可以選擇在單元格上直接輸入數(shù)據(jù)。這樣即可以保證輸入的規(guī)范,也兼顧了效率。
MFC;MFCGrid;按鈕單元格
1.1 MFC簡介
MFC(Microsoft Foundation Classes),是一個微軟公司提供的類庫(class libraries),以 C++類的形式封裝了Windows的API,并且包含一個應用程序框架,以減少應用程序開發(fā)人員的工作量。其中包含的類包含大量Windows句柄封裝類和很多Windows的內(nèi)建控件和組件的封裝類。目前,許多功能強大控件就是基于MFC庫開發(fā)的,MFCGrid就是其中之一。
1.2 MFCGrid控件簡介
MFCGrid控件是一款基于MFC技術的開源表格控件,它支持豐富的界面表現(xiàn)形式和用戶操作,被廣泛應用于MFC應用程序中。MFCGrid擁有許多常用的單元格類,如下表所示:
類名稱功能CGridCellCheck 復選框單元格,允許用戶選擇多個單元格CGridCellCombo 下拉列表框單元格,允許用戶點擊單元格上的下拉列表設置單元格內(nèi)容CGridCellDateTime 日期單元格,要求必須輸入時間格式的內(nèi)容CGridCellNumeric 數(shù)字單元格,要求輸入類型必須為數(shù)字CGridURLCell URL單元格,用戶點擊單元格時,以單元格內(nèi)容為URL地址打開網(wǎng)頁
MFCGrid提供的單元格式類型雖然比較豐富,但是其缺少了一個常用的單元格類型:按鈕型,即在單元格上有一個按鈕,點擊時可以出現(xiàn)界面供用戶選擇數(shù)據(jù),用戶也可以選擇在單元格上直接輸入數(shù)據(jù)。這樣即可以保證輸入的規(guī)范,也兼顧了效率。
由于工作上的需要,筆者決定對MFCGrid的單元格進行擴展,開發(fā)能夠在MFCGrid控件上運行的帶按鈕的單元格類CGridButtonCell。
2.1 基本功能
CGridButtonCell的基本功能要求如下:
(1)繼承原有CGridCell的編輯框,可以手工輸入,也可以讀取點擊按鈕調(diào)出界面上選擇的內(nèi)容。
(2)響應按鈕的點擊事件。
(3)每個按鈕單元格列上的按鈕在點擊時調(diào)用的方法彼此獨立,互不相同。
要實現(xiàn)上述功能,首先要在每個單元格基礎類CGridCell上繪制出按鈕控件,然后為其提供一個接口,供不同的對象調(diào)用,以達到每個按鈕調(diào)用不同方法的目的。
2.2 按鈕繪制
CGridButtonCell通過繼承從MFCGrid的CGridCell類,并重寫Draw方法,可以達到繪制按鈕的目的,關鍵代碼如下:
BOOL CGridCellButton::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd /* = TRUE */)
{
…
pDC-〉DrawFrameControl(rect, DFC_BUTTON,m_bPushing?DFCS_BUTTONPUSH |DFCS_PUSHED:DFCS_BUTTONPUSH); //繪制按鈕
pDC-〉DrawText(GetText(), -1, rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);//設置按鈕上的文字
…
}
2.3 按鈕事件實現(xiàn)
按鈕事件主要包括按下ClickDown和彈起事件Click,可以通過覆蓋父類CGridCell的同名方法實現(xiàn)。
void CGridCellButton::OnClickDown(CPoint PointCellRelative)
{
….
m_bPushing = TRUE; //將設置按下標志位,決定繪制樣式
GetGrid()-〉InvalidateRect(m_Rect); //觸發(fā)繪制事件,保證按鈕狀態(tài)與操作一致
…
}
void CGridCellButton::OnClick( CPoint PointCellRelative )
{
….
m_bPushing = FALSE;
GetGrid()-〉InvalidateRect(m_Rect);
…
}
為了能夠正確判斷用戶是否了按鈕,而不是按鈕所在的單元格的其他區(qū)域,可以通過判斷點擊事件所在的點是否在按鈕的區(qū)域內(nèi)位置實現(xiàn),代碼如下:
CRect CGridCellButton::GetButtonPlacement() //獲取按鈕區(qū)域
{
int nWidth = GetSystemMetrics(SM_CYHSCROLL);
CRect place = m_Rect + CSize(GetMargin(),GetMargin());
place.top=m_Rect.top;
place.bottom=m_Rect.bottom;
place.left=m_Rect.left+m_Rect.Width()-m_BtnWidth;
place.right=m_Rect.left+m_Rect.Width();
return place;
}
然后通過CRect的PtInRect方法,判斷記錄用戶點擊點PointCellRelative變量是否在按鈕控件的區(qū)域范圍中即可。這樣可以根據(jù)用戶點擊區(qū)域,判斷用戶是需要在CGridCellButton中手工錄入數(shù)據(jù)還是點擊按鈕選擇數(shù)據(jù)。
2.4 按鈕列的事件響應
(1)實現(xiàn)思想。ButtonCell最關鍵的功能是可以對每個 CGridButtonCell的按鈕在點擊時都可以調(diào)用不同的方法,而這些方法必須由調(diào)用它的外部類來決定。
考慮到程序的穩(wěn)定性和兼容性,筆者采用了類似 Java的“Listener”模式,通過預先定義一個事件類CgridCellButtonClickListener,其內(nèi)部有一個 OnClick的虛函數(shù),每個 CGridButtonCell都有一個CGridCellButtonClickListener類指針 m_pCellBtnLi,在CGridButtonCell的 ClickDown事件被觸發(fā)時,如果pCellBtnLi不為 NULL,則調(diào)用 pCellBtnLis所指向的CGridCellButtonClickListener中的OnClick方法。這樣,需要調(diào)用 ButtonCelll的外部類只要實現(xiàn)多個繼承了CGridCellButtonClickListener的子類,覆蓋其OnClick方法,在其中加入自己的方法,然后將這些子類通過SetButtonClickListener 方法注冊到 CGridButtonCell實例上,就可以實現(xiàn)按鈕對不同方法。下圖為類UML圖
(2)功能類及其調(diào)用。首先在CGridButtonCell的點擊事件中添加對 CGridCellButtonClickListener的點擊事件的調(diào)用,代碼如下:
void CGridCellButton::OnClick( CPoint PointCellRelative )
{
…
if(m_pCellBtnLi!=NULL){ // 如果CGridCellButtonClickListener不為null則調(diào)用
m_pCellBtnLi-〉OnClick(PointCellRelative);
}
….
}
上述代碼中,m_pCellBtnLi為CGridButtonCell的成員變量,類型為 CGridCellButtonClickListener,可以通過SetButtonClickListener方法修改。
假設CDlgForm為擁有MFCGrid控件的窗體類,MFCGrid的第一列為按鈕單元格列。其事件處理的CGridCellButtonClickListener類定義.h文件如下:
class CButtonCOL1_BtnClickListener:public CGridCellButtonClickListener
{
public:
CDlgSettingStd *m_pForm;
CButtonCOL1_BtnClickListener (CDlgForm*p){m_pForm=p;};
protected:
virtual void OnClick(CPoint PointCellRelative);
private: ~ CButtonCOL1_BtnClickListener ();
};
.cpp文件定義如下:
void
CButtonCOL1_BtnClickListener::OnClick(CPoint
PointCellRelative )
{
CCellID
id=m_pForm-〉m_Grid.GetCellFromPt(PointCellRelative);
m_pForm-〉SelLayerName(id.row,id.col); // 在CDlgForm中定義需要調(diào)用的方法
}
調(diào)用時,將定義的CButtonCOL1_BtnClickListener實例添加到CGridButtonCell實例,代碼如下:
CButtonCOL1_BtnClickListener * p=new CButtonCOL1_BtnClickListener (this);
pBtnCell-〉SetButtonClickListener(p);
這樣,在點擊按鈕時,只要 CGridButtonCell設置了CGridCellButtonClickListener的子類的指針,子類中定義OnClick事件就會被調(diào)用。
至此,筆者基本實現(xiàn)了CGridButtonCell的主要功能,并將其運用到工作中,取得了良好的效果,但該類仍存在一些功能上的不足,例如 MFCGrid支持用戶的拖放操作,在CGridButtonCell間進行拖放時,會出現(xiàn) CGridButtonCell上的按鈕沒有隱藏的問題,筆者將對其進行完善。
[1] 侯俊杰.深入淺出 MFC 第二版[M].華中科技大學出版社,2001.
[2] (美)Stephen Dewhurst.C++必知必會[M].人民郵電出版社,2010.
Realization of ButtonCell function on MFCGrid control
Abstrsct:Though The MFCGrid control provides rich celltypes for using,but it lacks a type which is used quit often:button cell type. There is a button on the gridcell,users can choose the data item on the form which invokes by the button-clicked or input the data themselves,it can make sure input data correct,and taking into account the efficiency.
MFC;MFCGrid;ButtonCell
TP273
A
1008-1151(2012)03-0014-02
2012-01-24
唐夏華(1981-),男,湖南人,廣西華藍設計(集團)有限公司信息中心工程師,研究方向為企業(yè)信息化。