tags:

views:

406

answers:

1

I'm new to MFC (coming from C# and Java) and figuring things out.

Consider a dialog with three text boxes. I have subclassed CEdit to CMyEdit, and the three text boxes are hooked up to CMyEdit variables in the dialog class.

I want to allow the dialog class to "know" when any of the three text boxes has been clicked with the left mouse button. I have found examples of how to add an ON_WM_LBUTTONDOWN handler to my CMyEdit class. Works great, but the handler is in the CMyEdit class only. Suppose that whenever one of the text boxes is clicked, I want the dialog to disable the other two. How can I get the dialog notified of the left-click?

This is a completely contrived and simplified example. I don'nt actually have an app where I'm worried about left clicks in text boxes. But I think the fact that I can't figure out how to do it indicates a fundamental misunderstanding of how to deal with UI events in MFC.

Coming from the world of C#, where everything is done for me and I have direct access to any of the events I want (got focus, mouse double click, whatever) I'm very confused on why certain events are special and provide easy access. In the case of CEdit, I don't understand why got focus, kill focus, change, and several others are "directly" available to me with no problem, but other events, like mouse click, are not.

But back to my actual question: in the scenario described above, how can I get the dialog notified of the left mouse clicks on the text boxes? Do the text boxes need to raise events or send messages (or something else) to the dialog?

+1  A: 

Add a WM_LBUTTONUP handler to your message map

ie

BEGIN_MESSAGE_MAP(CYourDialog, CDialog)
    ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

It is easiest to do this by adding an event handler to the window. This is most easily done through the resource editor. Go to the properties page then go to the messages section. Then add a function for WM_LBUTTONUP.

Finally you could fill in the function as follows.

void CYourDialog::OnLButtonUp(UINT nFlags, CPoint point) { // Grab the 3 (or more) edit control CEdit* pEdit1 = (CEdit*)GetDlgItem( ID_YOUR_EDIT_CONTROL1 ); CEdit* pEdit2 = (CEdit*)GetDlgItem( ID_YOUR_EDIT_CONTROL2 ); CEdit* pEdit3 = (CEdit*)GetDlgItem( ID_YOUR_EDIT_CONTROL3 );

// Grab the edit control window rects in screen coords.
CRect edit1Rect;
CRect edit2Rect;
CRect edit3Rect;
pEdit1->GetWindowRect( &edit1Rect );
pEdit2->GetWindowRect( &edit2Rect );
pEdit3->GetWindowRect( &edit3Rect );

// Convert to client coordinates relative to their parent (ie this) window.
ScreenToClient( edit1Rect );
ScreenToClient( edit2Rect );
ScreenToClient( edit3Rect );

// Test if the point passed in to this function is in the control's rectangle.
const BOOL bEnable1 = edit1Rect.PtInRect( edit1Rect );
const BOOL bEnable2 = edit2Rect.PtInRect( edit2Rect );
const BOOL bEnable3 = edit3Rect.PtInRect( edit3Rect );

// Enable the window that was clicked on and disable the others.
pEdit1->EnableWindow( bEnable1 );
pEdit2->EnableWindow( bEnable2 );
pEdit3->EnableWindow( bEnable3 );

// Set keyboard focus to the relevant control
if  ( bEnable1 )
{
 pEdit1->SetFocus();
}
else if ( bEnable1 )
{
 pEdit2->SetFocus();
}
else if ( bEnable1 )
{
 pEdit3->SetFocus();
}

CDialog::OnLButtonUp(nFlags, point);

}

This will, essentially, hit test and if the hit test is in an edit window it will enable it, disable the others and give it keyboard focus.

Goz
Thanks Goz for the code, I see that will indeed accomplish what I asked. It's not really what I was hoping for, though. What's bugging me is this: as I mentioned, I've subclassed the CEdit to CMyEdit, and handled the ON_WM_LBUTTONDOWN message there. So the CMyEdit objects "know" when they have been clicked. Isn't there some way for them to notify the dialog that they have been clicked, rather than doing all the hit test stuff? That makes more sense to me, but perhaps that's just not the way to do it.
Rob3C
Well you know what the parent class is ... you could always just call a function on it. It would tie you edit box to your dialog somewhat though. I suppose you could derive a "CMyDialog" from CDialog and ad the functionality there ...
Goz