首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

《programming windows》中的一个异常

2012-02-25 
《programmingwindows》中的一个错误这是WINDOWS程序设计里第6章鼠标测试里的一段代码,我想测试一下WM_SETFO

《programming windows》中的一个错误
这是WINDOWS程序设计里第6章鼠标测试里的一段代码,我想测试一下WM_SETFOCUS消息的触发条件,就在父窗口的消息处理函数里的WM_SETFOCUS后面加了几行代码,结果确在弹出一个窗口后点确定又会弹出,如此一共会弹出16个,这是什么意思啊,难道父窗口里产生了16个WM_SETFOCUS消息?或者是我对窗口的某些操作导致它又产生了WM_SETFOCUS消息?还有就是为什么子窗口创建后再点击子窗口,父窗口没有接收到WM_SETFOCUS消息?
我记得programming windows上的原话是"实际上当你在子窗口上单击的时候,情况有些复杂,这是是父窗口而不是自窗口获取焦点"难道说这句话有问题?

#include <windows.h>

#define DIVISIONS 5


LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ;

int idFocus = 0 ;

TCHAR szChildClass[] = TEXT ("Checker4_Child") ;


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

static TCHAR szAppName[] = TEXT ("Checker4") ;

HWND hwnd ;

MSG msg ;

WNDCLASS wndclass ;



wndclass.style = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc = WndProc ;

wndclass.cbClsExtra = 0 ;

wndclass.cbWndExtra = 0 ;

wndclass.hInstance = hInstance ;

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName = NULL ;

wndclass.lpszClassName = szAppName ;



if (!RegisterClass (&wndclass))

{

MessageBox (NULL, TEXT ("Program requires Windows NT!"),

szAppName, MB_ICONERROR) ;

return 0 ;

}



wndclass.lpfnWndProc = ChildWndProc ;

wndclass.cbWndExtra = sizeof (long) ;

wndclass.hIcon = NULL ;

wndclass.lpszClassName = szChildClass ;



RegisterClass (&wndclass) ;

hwnd = CreateWindow (szAppName, TEXT ("Checker4 Mouse Hit-Test Demo"),

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;

UpdateWindow (hwnd) ;



while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;

}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)

{

static HWND hwndChild[DIVISIONS][DIVISIONS] ;

int cxBlock, cyBlock, x, y ;

HWND hwnd1;

switch (message)

{

case WM_CREATE :

for (x = 0 ; x < DIVISIONS ; x++)

for (y = 0 ; y < DIVISIONS ; y++)

hwndChild[x][y] = CreateWindow (szChildClass, NULL,

WS_CHILDWINDOW | WS_VISIBLE,

0, 0, 0, 0,

hwnd, (HMENU) (y << 8 | x),

HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),

NULL) ;

return 0 ;

case WM_SIZE :

cxBlock = LOWORD (lParam) / DIVISIONS ;

cyBlock = HIWORD (lParam) / DIVISIONS ;



for (x = 0 ; x < DIVISIONS ; x++)

for (y = 0 ; y < DIVISIONS ; y++)

MoveWindow ( hwndChild[x][y],

x * cxBlock, y * cyBlock,

cxBlock, cyBlock, TRUE) ;

return 0 ;



case WM_LBUTTONDOWN :

MessageBeep (0) ;

return 0 ;


// On set-focus message, set focus to child window

case WM_SETFOCUS:

hwnd1=SetFocus (GetDlgItem (hwnd, idFocus)) ;
wsprintf((LPWSTR)buffer,L"%d",hwnd1)
MessageBox(hwnd,(LPCWSTR)buffer,(LPCWSTR)"",NULL);

return 0 ;


// On key-down message, possibly change the focus window


case WM_KEYDOWN:

x = idFocus & 0xFF ;

y = idFocus >> 8 ;


switch (wParam)

{

case VK_UP: y-- ; break ;

case VK_DOWN: y++ ; break ;

case VK_LEFT: x-- ; break ;

case VK_RIGHT: x++ ; break ;

case VK_HOME: x = y = 0 ; break ;

case VK_END: x = y = DIVISIONS - 1 ; break ;

default: return 0 ;

}


x = (x + DIVISIONS) % DIVISIONS ;

y = (y + DIVISIONS) % DIVISIONS ;


idFocus = y << 8 | x ;


SetFocus (GetDlgItem (hwnd, idFocus)) ;

return 0 ;


case WM_DESTROY :

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}


LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message,

WPARAM wParam, LPARAM lParam)

{

HDC hdc ;

PAINTSTRUCT ps ;

RECT rect ;



switch (message)

{

case WM_CREATE :

SetWindowLong (hwnd, 0, 0) ; // on/off flag

return 0 ;


case WM_KEYDOWN:

// Send most key presses to the parent window



if (wParam != VK_RETURN && wParam != VK_SPACE)

{

SendMessage (GetParent (hwnd), message, wParam, lParam) ;

return 0 ;

}

// For Return and Space, fall through to toggle the square



case WM_LBUTTONDOWN :

SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;

SetFocus (hwnd) ;

InvalidateRect (hwnd, NULL, FALSE) ;

return 0 ;


// For focus messages, invalidate the window for repaint



case WM_SETFOCUS:

idFocus = GetWindowLong (hwnd, GWL_ID) ;


// Fall through


case WM_KILLFOCUS:

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;



case WM_PAINT :

hdc = BeginPaint (hwnd, &ps) ;



GetClientRect (hwnd, &rect) ;

Rectangle (hdc, 0, 0, rect.right, rect.bottom) ;


// Draw the "x" mark



if (GetWindowLong (hwnd, 0))

{

MoveToEx (hdc, 0, 0, NULL) ;

LineTo (hdc, rect.right, rect.bottom) ;

MoveToEx (hdc, 0, rect.bottom, NULL) ;

LineTo (hdc, rect.right, 0) ;

}

// Draw the "focus" rectangle



if (hwnd == GetFocus ())

{

rect.left += rect.right / 10 ;

rect.right -= rect.left ;

rect.top += rect.bottom / 10 ;

rect.bottom -= rect.top ;


SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;

SelectObject (hdc, CreatePen (PS_DASH, 0, 0)) ;

Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom) ;

DeleteObject (SelectObject (hdc, GetStockObject (BLACK_PEN))) ;

}


EndPaint (hwnd, &ps) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}

[解决办法]
我没有测试你的代码,但我看了一下,你在窗口的某个控件获得焦点时就会弹出一个信息框。这样做会使原来的对话框上的控件失去焦点,当你点信息框的确定关闭信息框后,焦点又重回到了原来的那个控件,那样应该再次触发WM_SETFOCUS才对,以此推理,在弹出这个信息框后应该进入一个死循环而不是16个才对。

我建一个win32工程试一下你的代码。

[解决办法]
在VC6.0里有一个小工具叫SPY++,你用他看窗口收到了多少SETFOCUS不就行了吗!

热点排行