5/19/09

double action mfc c++ button








in this double action mfc c++ button tutorial we created twofold hover button with 2 tooltips


Depending on the location of the mouse cursor it performs different action whether it is addition or subtraction







DOWLOADS

This tutorial use reflected message to handle the onclicked message since it is a custom control the mouse clicked can not be handled in the dialog class

It is the hardest example I have ever made

To start the application


1- Start new MFC exe application and name it Hashi or else accept default settings
2- In the resource View make add the following bitmaps

and name them as IDB_BITMAP_PLUS_DOWN , IDB_MINUS_HOVER , IDB_MINUS_DOWN , IDB_LUS_HOVER ,IDB_BITMAP_PLUS_DOWN in order ;
make of dimension 200 ,60 pixels do u better if you have

3- Insert new class from insert menu and name it C_Double_task derived from CButton
4-Add the following data members
CBitmap m_bmp_normal_pic ,m_bmp_subtract_hover ,m_bitmap_subtract_down,m_bt_addition_hover ,m_bmp_addition_pushed;
enum Btn_Condition{ NORMAL ,MINUS_HOVER ,MINUS_DOWN,PLUS_OVER,PLUS_DOWN} ;
Btn_Condition m_previous_Mode ,m_present_mode ;
// five bitmaps and enumerators for statuses

5-Add new constructor ( five parameters ) as follows

C_Double_Task::C_Double_Task(int nornel, int negative_over, int neg_dowm, int plus_hovrt, int plus_pressed)
{

m_present_mode =NORMAL ;
/

m_bmp_normal_pic.LoadBitmap(nornel) ;
m_bmp_subtract_hover.LoadBitmap(negative_over) ;
m_bitmap_subtract_down.LoadBitmap(neg_dowm) ;
m_bt_addition_hover.LoadBitmap(plus_hovrt);
m_bmp_addition_pushed.LoadBitmap(plus_pressed) ;
// loading pictures
}


5-Add the following message handlers and virtual functions

first with DrawItem virtual function


void C_Double_Task::DrawItem(LPDRAWITEMSTRUCT lp_Draw_Items_Struct)
{

CDC *pMyDC =CDC::FromHandle(lp_Draw_Items_Struct->hDC);
CDC memDC_item ;

memDC_item.CreateCompatibleDC(pMyDC);
CBitmap* p_bitmap_mfc ;
switch(m_present_mode) {
// or use if statements
case NORMAL :
p_bitmap_mfc = memDC_item.SelectObject( &m_bmp_normal_pic);
break ;
case MINUS_HOVER :
p_bitmap_mfc = memDC_item.SelectObject( &m_bmp_subtract_hover);

break ;
case MINUS_DOWN :

p_bitmap_mfc = memDC_item.SelectObject( &m_bitmap_subtract_down);

break ;

case PLUS_OVER :
p_bitmap_mfc = memDC_item.SelectObject( &m_bt_addition_hover);

break ;

case PLUS_DOWN :

p_bitmap_mfc = memDC_item.SelectObject( &m_bmp_addition_pushed);
break ;
}
pMyDC->BitBlt( 0,0, lp_Draw_Items_Struct->rcItem.right -lp_Draw_Items_Struct->rcItem.left ,lp_Draw_Items_Struct->rcItem.bottom -lp_Draw_Items_Struct->rcItem.top ,&memDC_item ,0,0,SRCCOPY); memDC_item.SelectObject(p_bitmap_mfc) ; memDC_item.DeleteDC(); }

void C_Double_Task::OnLButtonDown(UINT nFlags, CPoint point)
{
SetCapture();

CRect ButtonRect ;
GetClientRect(ButtonRect) ;

m_previous_Mode =m_present_mode ;
m_present_mode =PLUS_DOWN ;
if(point.x > ButtonRect.left +ButtonRect.Width()/2 {
m_previous_Mode =m_present_mode ;
m_present_mode =MINUS_DOWN ;
}
CButton::OnLButtonDown(nFlags, point); }

void C_Double_Task::OnLButtonUp(UINT nFlags, CPoint point)
{

CRect upRect ;
GetClientRect(upRect) ;
CRect rect_left = upRect ;

rect_left .right = upRect.right/2 ;
if(PtInRect(upRect,point)) {
if(PtInRect(rect_left,point )) {
m_previous_Mode =m_present_mode ;

m_present_mode =PLUS_OVER ;
ReleaseCapture();

}

else
{
m_previous_Mode =m_present_mode ;
m_present_mode =MINUS_HOVER ;
ReleaseCapture();
}
}
else {

m_previous_Mode =m_present_mode ;
m_present_mode =NORMAL ;
ReleaseCapture();

}
CButton::OnLButtonUp(nFlags, point); }
void C_Double_Task::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rec_total ;
GetClientRect(rec_total) ;
CRect Rec_right = rec_total ;
Rec_right.left = rec_total.right/2 ;
CRect Rct_left = rec_total; Rct_left.right =rec_total.right/2 ;
if( PtInRect( rec_total ,point )){
if( PtInRect( Rec_right ,point )){
m_previous_Mode =m_present_mode ;
m_present_mode =MINUS_HOVER ;
Invalidate(FALSE) ;
} else
{
m_previous_Mode =m_present_mode ;
m_present_mode =PLUS_OVER ;
Invalidate(FALSE) ;
} } else if((m_previous_Mode == PLUS_DOWN || m_previous_Mode ==MINUS_DOWN) && PtInRect(Rec_right ,point)){
m_previous_Mode =m_present_mode ;
m_present_mode =MINUS_DOWN ; } else if((m_previous_Mode == PLUS_DOWN || m_previous_Mode ==MINUS_DOWN) && PtInRect(Rct_left ,point)){ m_previous_Mode =m_present_mode ; m_present_mode =PLUS_DOWN ; } else{ m_previous_Mode =m_present_mode ; m_present_mode =NORMAL ; Invalidate(FALSE) ; } TRACKMOUSEEVENT tn_Events ;
tn_Events.cbSize =sizeof(TRACKMOUSEEVENT) ;

tn_Events.dwFlags = TME_LEAVE ;

tn_Events.hwndTrack= m_hWnd ;
_TrackMouseEvent(&tn_Events) ;
CButton::OnMouseMove(nFlags, point);
}


void C_Double_Task::OnMouseLeave() {
m_previous_Mode =m_present_mode ;
m_present_mode =NORMAL ;
Invalidate() ;
}

and finally add onclicked
afx_msg void OnClicked(); in class header file

ON_CONTROL_REFLECT(BN_CLICKED, OnClicked)

in the begin message map section and add this to your cpp file void C_Double_Task::OnClicked() { DWORD dwpos = GetMessagePos() ;
CPoint pt ;

pt.x = LOWORD(dwpos );
pt.y = HIWORD(dwpos) ;
CRect client_rectangle ;
GetClientRect( client_rectangle) ;
CString strA , strB ;
double db_a ,db_b ;
GetParent()->GetDlgItemText(IDC_NUM1,strA) ; GetParent()->GetDlgItemText(IDC_NUM2,strB) ;
db_a = atof(strA);
db_b= atof(strB);
double result ;
result = db_b + db_a ;
CRect leftRect ;
leftRect = client_rectangle ;
leftRect.right = client_rectangle .left +client_rectangle.Width()/2;
if(leftRect.PtInRect(pt)) result = db_b - db_a ;
CString Str_result ;
Str_result.Format("%3.2f",result);
GetParent()->SendMessage(UDM_REGION_CLICKED, result);
}
lastly add this to your class header ;
static const UINT UDM_REGION_CLICKED = ::RegisterWindowMessage(_T("UDM_REGION_CLICKED-{23C118F8-01}"));

now we finished with the custom class Derived from Cbutton

Now we are in the dialog class
6- In the class wizard add the following data member
7- edit the constructor as follows
CHashiDlg::CHashiDlg(CWnd* pParent /*=NULL*/) : CDialog(CHashiDlg::IDD, pParent),m_two_actions_botn(IDB_NORMAL ,IDB_MINUS_HOVER ,IDB_MINUS_DOWN , IDB_LUS_HOVER , IDB_BITMAP_PLUS_DOWN)
{
//{{AFX_DATA_INIT(CHashiDlg) m_numB = _T(""); //}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }


8-as pretranslate message handler as follows
C_Double_Task m_two_actions_botn;
and for edit controls add member variable with names like m_numA , m_numB ,m_results of type string

in the dialog class header add afx_msg LRESULT OnRegionClicked( WPARAM wParam, LPARAM lParam );

in the begin message map section in the cpp file ON_REGISTERED_MESSAGE(UDM_REGION_CLICKED, OnRegionClicked)
and at the end of the cpp add
LRESULT CHashiDlg::OnRegionClicked( WPARAM wParam, LPARAM param ) {
CString resl ;

resl.Format("%3.3",wParam);

SetDlgItemText( IDC_RESULT , resl) ;
return (0);
}

finally build the application and trying clicking on the right half and left half
BOOL CHashiDlg::PreTranslateMessage(MSG* pMsg) {
if( m_vc_tooltip.m_hWnd) m_vc_tooltip.RelayEvent(pMsg) ;
return CDialog::PreTranslateMessage(pMsg); }

Note this is a draft not working

4 comments:

leave me messege