Author : Unknown
Page : << Previous 5 Next >>
from one window to another, and we can add message handlers for them. All user-defined messages must have a message ID equal to or greater than WM_USER.
In the sample, a new message WM_BTNPOS is defined in file "MButton.h":
#define WM_BTNPOS WM_USER+1000
By doing this, WM_BTNPOS becomes a message that can be used in the application. Please note that this message can not be sent to other applications. If we want to send user-defined message among different applications, we need to register that message to the system.
In function MCBitmapButton::OnLButtonUp(...), user defined message WM_BTNPOS is sent to the parent window, with the current mouse position stored in LPARAM parameter:
(Code omitted)
First the default implementation of function OnLButtonUp(...)is called. Then a CWnd type pointer of parent window is obtained by calling function CWnd::GetParent(). Class CWnd has several member functions that can be used to send Windows? message, the most commonly used ones are CWnd:: SendMessage(...) and CWnd::PostMessage(...). The difference between the two functions is that after sending out the message, CWnd::SendMessage(...) does not return until the message has been processed by the target window, and CWnd::PostMessage(...) returns immediately after the message has been sent out. In the sample, function CWnd::PostMessage(...) is used to send WM_BTNPOS message.
All messages in Windows have two parameters, WPARAM and LPARAM. For Win32 applications, both WPARAM and LPARAM are 32-bit integers. They can be used to send additional information.
In MFC, usually message parameters are passed as arguments to message handlers, so they are rarely noticed. For example, for message WM_LBUTTONDOWN, its WPARAM parameter is used to indicate if any of CTRL, ALT, or SHIFT key is held down when the mouse button is up. In the message handler, this information is mapped to the first parameter of CWnd::OnLButtonUp(...). Again, its LPARAM parameter contains the information of current mouse position, which is mapped to the second parameter of CWnd::OnLButtonUp(...). Both CWnd::SendMessage(...) and CWnd::PostMessage(...) have three parameters, the first of which specifies message ID, and the rest two are WPARAM and LPARAM parameters. If we don't want to send additional message, we can pass 0 to both of them.
In the sample, we need to use both parameters: the parent window needs to know the control ID of the button; also, it needs to know the current mouse position.
The button's ID can be retrieved by calling function CWnd::GetDlgCtrlID(), it will be sent through WPARAM parameter to the button's parent. The x and y coordinates of mouse cursor can be combined together to form an LPARAM parameter by using MAKELPARAM macro. Here, macro MAKELPARAM can combine two 16-bit numbers to form a 32-bit message. If we provide two 32-bit numbers, only the lower 16 bits will be used (Of course, screen coordinates won't use more than 16 bits).
The message is received and processed in class CBtnDlg. In MFC, general message can be mapped to a member function by using ON_MESSAGE macro. This type of message handler has two parameters, one for receiving WPARAM information and the other for receiving LPARAM information. Also, it must return a LONG type value.
The following code fragment shows how member function OnBtnPos(...) is declared in class CBtnDlg (It will be used to receive WM_BTNPOS message):
class CBtnDlg : public CDialog
{
......
protected:
......
afx_msg LONG OnBtnPos(UINT, LONG);
DECLARE_MESSAGE_MAP()
};
In the implementation file, ON_MESSAGE macro is added as follows:
BEGIN_MESSAGE_MAP(CBtnDlg, CDialog)
......
ON_MESSAGE(WM_BTNPOS, OnBtnPos)
END_MESSAGE_MAP()
The control ID and the mouse information can be extracted within the message handler as follows:
(Code omitted)
Sample
Sample 6\Btn has a four-arrow bitmap button. First a button resource is added to the dialog template, whose ID is IDC_PLAY_POS and caption text is "PLAYPOS" (bitmaps will be loaded through automatic method). Two new bitmap resources "PLAYPOSU" and "PLAYPOSD" are also added to the application, which will be used to draw button's "up" and "down" states.
We need to know the sizes and the positions of four arrows within the bitmap button so we can judge if the mouse cursor is over any of the arrows. Within class CBtnDlg, a CRect type array with size of 4 is declared for this purpose. Their values are initialized in function CBtnDlg::OnInitDialog(). Also an MCBitmapButton type variable m_btnPlayPos is declared to implement this new button:
class CBtnDlg : public CDialog
{
......
protected:
......
MCBitmapButton m_btnPlayPos;
......
CRect m_rectBtnPos[4];
......
};
The following portion of function CBtnDlg::OnInitDialog() shows how array m_rectBtnPos is initialized:
(Code omitted)
Here, we call function CWnd::GetClientRect() to retrieve the button size. We need to calculate the sizes and positions of the arrows after bitmaps have been loaded. This is because a button will be resized according to the bitmap size after it is initialized.
Function CBtnDlg::OnBtnPos(...) is implemented just for the purpose of demonstration: if any of the four arrows is pressed, a message box will pop up displaying a different message:
(Code omitted)
The application is now ready for compile. Based on this method, we can implement bitmap buttons with more complicated functionality.
7 Mouse Sensitive Button
Setting Capture
In this section, we are going to create a very special button. It is not a push button, nor a check box or radio button. The button has two states: normal and highlighted. Generally, the button will stay in normal state. When the mouse cursor is within the button's rectangle (with no mouse button being clicked), the button will become highlighted, and if the mouse moves out of the rectangle, the button will resume to normal state.
To implement this type of button, we need to trap mouse messages and implement handlers. One of the messages we need to handle is WM_MOUSEMOVE, which will be sent to a window if the mouse cursor is moving over the button. We need to respond to this message and set button's state to "highlighted" when the mouse cursor first comes into the button's rectangle. From now on, we need to keep an eye on the mouse's movement, if the mouse moves out of the rectangle, we need to resume button's normal state.
However, since message WM_MOUSEMOVE will only be sent to a window when the mouse cursor is within it, it is difficult to be informed of the event that mouse has just left the button's window. This is because once the mouse leaves, the button will not be able to receive WM_MOUSEMOVE message anymore.
To help us solve this type of problems, Windows? provides a technique that can be used to track mouse's activities after it leaves a window. This technique is called Capture. By using this method, we could capture all the mouse-related messages to one specific window, no matter where the mouse is.
We can call function CWnd::SetCapture() to set capture for a window. The capture can also be released by calling function ::ReleaseCapture(), which is a Win32 API function. Besides using this function, the capture can also be removed by the operating system under certain conditions. If this happens, the window that is losing capture will receive a WM_CAPTURECHANGED message.
New Class
Sample 7\Btn demonstrates how to implement "mouse sensitive button". In the application, a new class MCSenButton is created for this purpose, and is defined as follows:
(Code omitted)
The class contains only a constructor, two message handlers, and a Boolean type variable m_bCheck. Variable m_bCheck will be used to indicate the button's current state: it is TRUE if the button is currently highlighted, and is FALSE if the button is in the normal state. Within the constructor, this variable is initialized to FALSE:
MCSenButton::MCSenButton() : MCBitmapButton()
{
m_bCheck=FALSE;
}
Functions MCSenButton::OnMouseMove(...) and MCSenButton::OnCaptureChanged(...) are message handlers for WM_MOUSEMOVE and WM_CAPTURECHANGED respectively. Like all other types of messages, their message mapping macros should be added in the implementation file:
IMPLEMENT_DYNAMIC(MCSenButton, MCBitmapButton)
BEGIN_MESSAGE_MAP(MCSenButton, MCBitmapButton)
ON_WM_MOUSEMOVE()
ON_WM_CAPTURECHANGED()
END_MESSAGE_MAP()
Here, ON_WM_MOUSEMOVE and ON_WM_CAPTURECHANGED are message mapping macros defined by MFC.
The following two functions handle above two messages:
(Code omitted)
In function MCSenButton::OnMouseMove(...), if m_bCheck is FALSE, it means the button is in the normal state. In this case, we need to set mouse capture, change the button to "highlighted" state, and redraw the button. If the button is currently highlighted, we need to check the current position of mouse cursor, if it has moved out of the button window, we should resume button's normal state, and redraw the button. Here, CButton::SetState(...) is used to set the button to different states (it will cause the bitmap button to use the corresponding bitmap), and CWnd::Invalidate() is used to cause the button to be redrawn.
In function MCSenButton::OnCaptureChanged(...), we need to change m_bCheck back to FALSE, and resume button's normal state.
Implementation
In the sample, four new buttons are added to the application. The IDs of these new buttons are IDC_MOUSE_SEN_1, IDC_MOUSE_SEN_2, IDC_MOUSE_SEN_3 and IDC_MOUSE_SEN_4 respectively. An MCSenButton type array m_btnBmp (The array size is 4) is declared in class CBtnDlg and initialized in function CBtnDlg::OnInitDialog() as follows:
(Code omitted)
Here, we use subclass instead of automatic method to load bitmaps. Also, we use IDB_BITMAP_BTNUNCHECK and IDB_BITMAP_BTNCHECK to implement button's normal and highlighted states respectively.
Because mouse related messages are handled within the member functions of class MCSenButton, once we declare variables within it, the buttons will automatically become mouse sensitive. There is no need for us to write extra code for handling mouse messages outside the class.
Summary
1) We can use class CBitmapButton to implement bitmap buttons. To
Page : << Previous 5 Next >>