Irwan
July 1st, 2010, 10:05 PM
Hi,
I'm having problem. I have reduce the code to simplify the question.
In this code, I have create 3 child windows (or I refered as panel) to the the parent window (hwnd) in Client Area.
The App Handle = hInstance
The Main/Parent Window = hwnd
The Child Window to hwnd = hwndMsgPanel, hwndLeftPanel, hwndSplitterPanel
The problem:
1. I try to process WM_MOUSEMOVE in WndProc (for hwnd).
2. Whenever Cursor is x>0 in client area, it should change to IDC_SIZEWE.
3. Because x>0 is mean all the client area, so the cursor should change IDC_SIZEWE whenever it in client.
4. But it is not in case of my app. The cursor only change when it is in client area but not ontop of all the child window area (area which is sepcify to hwndMsgPanel, hwndLeftPanel, hwndSplitterPanel).
5. I suspect that, WndProc (for hwnd) do not process the message send to its child window (because hwndMsgPanel, hwndLeftPanel, hwndSplitterPanel is the child window to hwnd).
6. I test process the WM_MOUSEMOVE in the one of the child window, let say LeftPanelProc (wndProc for hwndLeftWnd). Now the cursor change to IDC_SIZEWE whenever the cursor ontop the hwndLeftPanel area. (The code is not show below as this is not the question).
7. But I suppose the message send to hwnd, and hwnd should able to handle its child right?
8. Moreover, the code in http://www.win32apicode.com/splitter.php is able to do it.
Why my app hwnd can't process mouse in its child window?
Thanks, I think this question will be easy for the you guys, the master. :)
#include <windows.h> // For Win32 API
// API Function Prototype
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK LeftPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK SplitterPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MsgPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
// Win32 API Structure Declaration
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
static TCHAR szAppName[] = TEXT("SplitterApp");
HBRUSH bgBrushA, bgBrushB, bgBrushC, bgBrushD;
// Main Window Class
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = bgBrushA = CreateSolidBrush(RGB(195,218,249)); // This is same with FrameBase.BgColor Property
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
// Left Panel Class
wndclass.lpfnWndProc = LeftPanelProc;
wndclass.hbrBackground = bgBrushB = CreateSolidBrush(RGB(255,255,255)); // This is same with LeftPanel.BgColor Property
wndclass.lpszClassName = TEXT("LeftPanel");
RegisterClass(&wndclass);
// Splitter Panel Class (divider between Left Panel & Work Panel)
wndclass.lpfnWndProc = SplitterPanelProc;
wndclass.hbrBackground = bgBrushC = CreateSolidBrush(RGB(255,0,0)); // This is same with SplitterPanel.BgColor Property
wndclass.lpszClassName = TEXT("SplitterPanel");
RegisterClass(&wndclass);
// Msg Panel Class
wndclass.lpfnWndProc = MsgPanelProc;
wndclass.hbrBackground = bgBrushD = CreateSolidBrush(RGB(255,255,0)); // This is same with LeftPanel.BgColor Property
wndclass.lpszClassName = TEXT("MsgPanel");
RegisterClass(&wndclass);
// Create Window for Main Window
hwnd = CreateWindow( szAppName,
szAppName,
WS_OVERLAPPEDWINDOW | SW_MAXIMIZE | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
900,
500,
NULL,
NULL,
hInstance,
szCmdLine);
// Message Pump
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Delete All Brush created to paint all panel & window background
DeleteObject(bgBrushA);
DeleteObject(bgBrushB);
DeleteObject(bgBrushC);
DeleteObject(bgBrushD);
return (int)msg.wParam;
}
// Main Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndLeftPanel, hwndSplitterPanel, hwndMsgPanel;
static CREATESTRUCT *cs;
RECT rect;
static HCURSOR hcSizingWE;
int MouseXPos, MouseYPos;
bool mouseOverFlag;
switch(iMsg){
case WM_CREATE :
cs = (CREATESTRUCT *)lParam; // For Application Handle hInstance
// Create Left Panel
hwndLeftPanel = CreateWindowEx( 0,
TEXT("LeftPanel"),
TEXT("Left Panel"),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
0, // Panel Coord. will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
0, // Panel Size will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
hwnd, // The Top Window Handle
0, // No menu for panel
cs->hInstance, // The App Handle
0);
// Create Splitter Panel
hwndSplitterPanel = CreateWindowEx( 0,
TEXT("SplitterPanel"),
TEXT("Splitter Panel"),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
0, // Panel Coord. will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
0, // Panel Size will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
hwnd, // The Top Window Handle
0, // No menu for panel
cs->hInstance, // The App Handle
0);
// Create Msg Panel
hwndMsgPanel = CreateWindowEx( 0,
TEXT("MsgPanel"),
TEXT("Message Panel"),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
0, // Panel Coord. will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
0, // Panel Size will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
hwnd, // The Top Window Handle
0, // No menu for panel
cs->hInstance, // The App Handle
0);
InvalidateRect(hwnd, &rect, TRUE);
break;
case WM_SIZE :
GetClientRect(hwnd, &rect);
// Set Panels Size and Position for first time
// To make sense on the numbering I use, following is the definition
// MsgPanel Height = 30
// LeftPanel Width = 250
// SplitterPanel Width = 500
MoveWindow(hwndMsgPanel, rect.left, rect.top, rect.right, 30, FALSE);
MoveWindow(hwndLeftPanel, rect.left, rect.top + 30, 250, rect.bottom-30, FALSE);
MoveWindow(hwndSplitterPanel, rect.left + 250, rect.top + 30, 50, rect.bottom-30, FALSE);
// Load App used Cursor
hcSizingWE = LoadCursor(NULL, IDC_SIZEWE);
InvalidateRect(hwnd, &rect, TRUE);
break;
case WM_MOUSEMOVE:
// The Test Flag
mouseOverFlag = 0;
// Convert Cursor Position from LPARAM
MouseXPos = (int) LOWORD(lParam);
MouseYPos = (int) HIWORD(lParam);
if (MouseXPos > 0 && GetCursor() != hcSizingWE)
SetCursor(hcSizingWE);
break;
case WM_CLOSE :
DestroyWindow(hwnd);
break;
case WM_DESTROY :
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK LeftPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE :
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK SplitterPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE :
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK MsgPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE :
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
I'm having problem. I have reduce the code to simplify the question.
In this code, I have create 3 child windows (or I refered as panel) to the the parent window (hwnd) in Client Area.
The App Handle = hInstance
The Main/Parent Window = hwnd
The Child Window to hwnd = hwndMsgPanel, hwndLeftPanel, hwndSplitterPanel
The problem:
1. I try to process WM_MOUSEMOVE in WndProc (for hwnd).
2. Whenever Cursor is x>0 in client area, it should change to IDC_SIZEWE.
3. Because x>0 is mean all the client area, so the cursor should change IDC_SIZEWE whenever it in client.
4. But it is not in case of my app. The cursor only change when it is in client area but not ontop of all the child window area (area which is sepcify to hwndMsgPanel, hwndLeftPanel, hwndSplitterPanel).
5. I suspect that, WndProc (for hwnd) do not process the message send to its child window (because hwndMsgPanel, hwndLeftPanel, hwndSplitterPanel is the child window to hwnd).
6. I test process the WM_MOUSEMOVE in the one of the child window, let say LeftPanelProc (wndProc for hwndLeftWnd). Now the cursor change to IDC_SIZEWE whenever the cursor ontop the hwndLeftPanel area. (The code is not show below as this is not the question).
7. But I suppose the message send to hwnd, and hwnd should able to handle its child right?
8. Moreover, the code in http://www.win32apicode.com/splitter.php is able to do it.
Why my app hwnd can't process mouse in its child window?
Thanks, I think this question will be easy for the you guys, the master. :)
#include <windows.h> // For Win32 API
// API Function Prototype
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK LeftPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK SplitterPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MsgPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
// Win32 API Structure Declaration
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
static TCHAR szAppName[] = TEXT("SplitterApp");
HBRUSH bgBrushA, bgBrushB, bgBrushC, bgBrushD;
// Main Window Class
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = bgBrushA = CreateSolidBrush(RGB(195,218,249)); // This is same with FrameBase.BgColor Property
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
// Left Panel Class
wndclass.lpfnWndProc = LeftPanelProc;
wndclass.hbrBackground = bgBrushB = CreateSolidBrush(RGB(255,255,255)); // This is same with LeftPanel.BgColor Property
wndclass.lpszClassName = TEXT("LeftPanel");
RegisterClass(&wndclass);
// Splitter Panel Class (divider between Left Panel & Work Panel)
wndclass.lpfnWndProc = SplitterPanelProc;
wndclass.hbrBackground = bgBrushC = CreateSolidBrush(RGB(255,0,0)); // This is same with SplitterPanel.BgColor Property
wndclass.lpszClassName = TEXT("SplitterPanel");
RegisterClass(&wndclass);
// Msg Panel Class
wndclass.lpfnWndProc = MsgPanelProc;
wndclass.hbrBackground = bgBrushD = CreateSolidBrush(RGB(255,255,0)); // This is same with LeftPanel.BgColor Property
wndclass.lpszClassName = TEXT("MsgPanel");
RegisterClass(&wndclass);
// Create Window for Main Window
hwnd = CreateWindow( szAppName,
szAppName,
WS_OVERLAPPEDWINDOW | SW_MAXIMIZE | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
900,
500,
NULL,
NULL,
hInstance,
szCmdLine);
// Message Pump
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Delete All Brush created to paint all panel & window background
DeleteObject(bgBrushA);
DeleteObject(bgBrushB);
DeleteObject(bgBrushC);
DeleteObject(bgBrushD);
return (int)msg.wParam;
}
// Main Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndLeftPanel, hwndSplitterPanel, hwndMsgPanel;
static CREATESTRUCT *cs;
RECT rect;
static HCURSOR hcSizingWE;
int MouseXPos, MouseYPos;
bool mouseOverFlag;
switch(iMsg){
case WM_CREATE :
cs = (CREATESTRUCT *)lParam; // For Application Handle hInstance
// Create Left Panel
hwndLeftPanel = CreateWindowEx( 0,
TEXT("LeftPanel"),
TEXT("Left Panel"),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
0, // Panel Coord. will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
0, // Panel Size will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
hwnd, // The Top Window Handle
0, // No menu for panel
cs->hInstance, // The App Handle
0);
// Create Splitter Panel
hwndSplitterPanel = CreateWindowEx( 0,
TEXT("SplitterPanel"),
TEXT("Splitter Panel"),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
0, // Panel Coord. will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
0, // Panel Size will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
hwnd, // The Top Window Handle
0, // No menu for panel
cs->hInstance, // The App Handle
0);
// Create Msg Panel
hwndMsgPanel = CreateWindowEx( 0,
TEXT("MsgPanel"),
TEXT("Message Panel"),
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
0, // Panel Coord. will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
0, // Panel Size will be handle in the WM_SIZE via
0, // MoveWindow(). No InvalidateRec() in this case
hwnd, // The Top Window Handle
0, // No menu for panel
cs->hInstance, // The App Handle
0);
InvalidateRect(hwnd, &rect, TRUE);
break;
case WM_SIZE :
GetClientRect(hwnd, &rect);
// Set Panels Size and Position for first time
// To make sense on the numbering I use, following is the definition
// MsgPanel Height = 30
// LeftPanel Width = 250
// SplitterPanel Width = 500
MoveWindow(hwndMsgPanel, rect.left, rect.top, rect.right, 30, FALSE);
MoveWindow(hwndLeftPanel, rect.left, rect.top + 30, 250, rect.bottom-30, FALSE);
MoveWindow(hwndSplitterPanel, rect.left + 250, rect.top + 30, 50, rect.bottom-30, FALSE);
// Load App used Cursor
hcSizingWE = LoadCursor(NULL, IDC_SIZEWE);
InvalidateRect(hwnd, &rect, TRUE);
break;
case WM_MOUSEMOVE:
// The Test Flag
mouseOverFlag = 0;
// Convert Cursor Position from LPARAM
MouseXPos = (int) LOWORD(lParam);
MouseYPos = (int) HIWORD(lParam);
if (MouseXPos > 0 && GetCursor() != hcSizingWE)
SetCursor(hcSizingWE);
break;
case WM_CLOSE :
DestroyWindow(hwnd);
break;
case WM_DESTROY :
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK LeftPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE :
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK SplitterPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE :
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK MsgPanelProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE :
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}