对windows程序设计书中的第七章例子的理解!有点困惑。

yiruirui0507 2010-12-18 01:32:17
/*-------------------------------------------------
CHECKER3.C -- Mouse Hit-Test Demo Program No. 3
(c) Charles Petzold, 1998
-------------------------------------------------*/

#include <windows.h>

#define DIVISIONS 5

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

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

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Checker3") ;
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 ("Checker3 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 ;

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 ;

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_LBUTTONDOWN :
SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;
InvalidateRect (hwnd, NULL, FALSE) ;
return 0 ;

case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;
Rectangle (hdc, 0, 0, rect.right, rect.bottom) ;

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) ;
}

EndPaint (hwnd, &ps) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

头一次遇到涉及到子窗口的问题,发现理解起来有困难。
RegisterClass注册了两个窗口类,关键的问题就在于子窗口跟父窗口的联系搞不明白。
父窗口的WM_CREATE中创建了25个子窗口且保留了对应的句柄,
问题1
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) ;
这句的理解,子窗口的风格必须加上WS_CHILDWINDOW|WS_VISIBLE吗?另外这里创建的25个子窗口咋么没大小?0,0,0,0 有点奇怪。(HMENU) (y << 8 | x)这个也不懂什么意思,没有涉及到菜单啊?
问题2
MoveWindow (hwndChild[x][y],
x * cxBlock, y * cyBlock,
cxBlock, cyBlock, TRUE) ;
当窗口尺寸发生变化时,移动子窗口到指定位置,并且重绘每个子窗口,但是在子窗口的消息处理中WM_PAINT
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;
Rectangle (hdc, 0, 0, rect.right, rect.bottom) ;

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) ;
}

EndPaint (hwnd, &ps) ;
return 0 ;
}
并没有做什么工作嘛,只是重新画了一下客户区矩形,请问这里又该如何理解?如果把MOVEWINDOW的TRUE改成FALSE会发生什么?
最后问题:
SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;
GETWINDOWLONG(HWND,0)这里的0是HWNDFIRST吧,也就是说看看窗口是否是处在父窗口的上面或者顶层,进行异或操作刚好让他相反。最后刷新客户区?我这理解的对否?
...全文
145 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
yiruirui0507 2010-12-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 szjeff2005 的回复:]
setwindowlong可以使用的偏移都是正偏移,从0开始,可以由使用者自行使用,但必须开始时要预留空间,相当于你要先申请相应的内存,所以就需要在注册时,对cbWndExtra进行赋值,这就是申请可用空间,但要注意申请的单位是以字节为单位的,但用setwindowlong和getwindowlong需要注意里面的long,它的偏移都是以long为单位的,所以对于WNDCLASS保留了一个LONG……
[/Quote]

ok!
zzw820626 2010-12-18
  • 打赏
  • 举报
回复
楼上都答完了,我来支持下
szjeff2005 2010-12-18
  • 打赏
  • 举报
回复
setwindowlong可以使用的偏移都是正偏移,从0开始,可以由使用者自行使用,但必须开始时要预留空间,相当于你要先申请相应的内存,所以就需要在注册时,对cbWndExtra进行赋值,这就是申请可用空间,但要注意申请的单位是以字节为单位的,但用setwindowlong和getwindowlong需要注意里面的long,它的偏移都是以long为单位的,所以对于WNDCLASS保留了一个LONG型字节,那当然偏移就是0了,所以你将偏移设为1,就没有用了。要想使用1,那么前面就使用2*sizeof(LONG),就可以了。
yiruirui0507 2010-12-18
  • 打赏
  • 举报
回复
为什么我把SETWINDOWLONG,GETWINDOWLONG的第二个参数都设置为1就没效果了呢?
难道只有NINDEX设置为0才能访问在窗口类中为每个窗口保留的额外内存吗?求解释!!!!!!!
yiruirui0507 2010-12-18
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 szjeff2005 的回复:]
1、在CreateWindow中没有给出窗口大小,只是因为在WM_SIZE消息中定位窗口时,还需要指定窗口大小,所以前面指定没有意义,当然你指定了,也可以,对结果没有影响,WM_CREATE消息产生后,还会继续处理WM_SIZE消息,对于HMENU,你需要再仔细看一下MSDN上面针对CreateWindow的说明,如果是产生子窗口中,这是子窗口的编号,不是菜单,不要被名字迷惑了
2、WM_PAI……
[/Quote]

谢谢,关于SETWINDOWLONG能详细介绍一下吗?分数绝不是问题,
SetWindowLong该函数改变指定窗口的属性.函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。
SETWINDOWLONG 这个我可以随便设置吧
比如我:SETWINDOWLONG(HWND,2,3)
那我GETWINDOWLONG(HWND,2)就能得到3?
是咋么跟
wndclass.cbWndExtra = sizeof (long) ;
联系在一起的,我没看出来有什么关系,谢谢!
szjeff2005 2010-12-18
  • 打赏
  • 举报
回复
1、在CreateWindow中没有给出窗口大小,只是因为在WM_SIZE消息中定位窗口时,还需要指定窗口大小,所以前面指定没有意义,当然你指定了,也可以,对结果没有影响,WM_CREATE消息产生后,还会继续处理WM_SIZE消息,对于HMENU,你需要再仔细看一下MSDN上面针对CreateWindow的说明,如果是产生子窗口中,这是子窗口的编号,不是菜单,不要被名字迷惑了
2、WM_PAINT消息比较重要,这是客户区的内容刷新,必须自己来实现,这是windows的窗口刷新机制来实现的,在区域无效后都会产生WM_PAINT消息,这同MoveWindow不太一样的,MoveWindow函数调用后,如果参数为TRUE,就会产生WM_PAINT消息,如果参数是FALSE,就不会产生WM_PAINT消息,所以如果你修改程序将参数个性为FALSE,那么刚开始显示时是一片空白,此时各子窗口没有WM_PAINT消息,所以就不会画图了
3、SetWindowLong主要是利用每个窗口的保留字节,用来识别打叉还是没有打叉,这是非常方便的,也是一种实现技巧,当然如果你不觉得麻烦,也可以设一个数组,同每个窗口对应,也可以,但就会麻烦一些,因为要判断是哪一个窗口

看回答清楚没有,可以给我点分了,紧缺中,也有问题想寻高手解答,呵呵
bingying19872008 2010-12-18
  • 打赏
  • 举报
回复
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) ;
这句的理解,子窗口的风格必须加上WS_CHILDWINDOW|WS_VISIBLE吗?

子窗口必须加WS_CHILDWINDOW|WS_VISIBLE,因为穿了参数hwnd进去,表示 正创建的窗口时hwnd的子窗口.
并且可见.MoveWindow 除了移动窗口外,还能改变窗口大小
schlafenhamster 2010-12-18
  • 打赏
  • 举报
回复
0, 0, 0, 0,表示默认,真正大小在:
MoveWindow (hwndChild[x][y], x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE) ;
cxBlock, cyBlock,中
就是因为子窗口不能有Menu所以用它来表示子窗口ID:(即控件ID)
(HMENU) (y << 8 | x)这个也不懂什么意思,没有涉及到菜单啊
yiruirui0507 2010-12-18
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 yihandrensunyong 的回复:]
帮顶下 太多了。。。
[/Quote]

这个很难吗?你给整理一下流程也行啊????

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧