对SETROP2一点疑问,取反疑问。在线等。

yiruirui0507 2011-01-25 04:57:07
#include <windows.h>

LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM) ;
HINSTANCE hinst;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("BlokOut1") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
hinst=hInstance;

wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = MainWndProc ;
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 ;
}

hwnd = CreateWindow (szAppName, TEXT ("Mouse Button 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 ;
}

void DrawBoxOutline (HWND hwnd, POINT ptBeg, POINT ptEnd)
{
HDC hdc ;

hdc = GetDC (hwnd) ;

SetROP2 (hdc, R2_NOT) ;
SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;

ReleaseDC (hwnd, hdc) ;
}

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL fBlocking, fValidBox ;
static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd ;
HDC hdc ;
PAINTSTRUCT ps ;

switch (message)
{
case WM_LBUTTONDOWN :
ptBeg.x = ptEnd.x = LOWORD (lParam) ;
ptBeg.y = ptEnd.y = HIWORD (lParam) ;

DrawBoxOutline (hwnd, ptBeg, ptEnd) ;

SetCursor (LoadCursor (NULL, IDC_CROSS)) ;

fBlocking = TRUE ;
return 0 ;

case WM_MOUSEMOVE :
if (fBlocking)
{
SetCursor (LoadCursor (NULL, IDC_CROSS)) ;

DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
//DrawBoxOutline (hwnd, ptBeg, ptEnd);
ptEnd.x = LOWORD (lParam) ;
ptEnd.y = HIWORD (lParam) ;

DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
//DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
}
return 0 ;

case WM_LBUTTONUP :
if (fBlocking)
{
DrawBoxOutline (hwnd, ptBeg, ptEnd) ;//白

ptBoxBeg = ptBeg ;
ptBoxEnd.x = LOWORD (lParam) ;
ptBoxEnd.y = HIWORD (lParam) ;

SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

fBlocking = FALSE ;
fValidBox = TRUE ;

InvalidateRect (hwnd, NULL, TRUE) ;
}
return 0 ;

case WM_CHAR :
if (fBlocking & (wParam == '\x1B'))
{
DrawBoxOutline (hwnd, ptBeg, ptEnd) ;

SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

fBlocking = FALSE ;
}
return 0 ;

case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
if (fValidBox)
{
SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ;
Rectangle (hdc, ptBoxBeg.x, ptBoxBeg.y,
ptBoxEnd.x, ptBoxEnd.y) ;
}

if (fBlocking)
{
SetROP2 (hdc, R2_NOT) ;
SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
}

EndPaint (hwnd, &ps) ;
return 0 ;

case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

SETROP2参数为R2_NOT,相信大家都知道什么意思,
关键在DrawBoxOutline 函数,关键代码
SetROP2 (hdc, R2_NOT) ;
SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y)

只绘制边框,内部为空。
简单点来说,DrawBoxOutline 第一次是画矩形(与屏幕象素相反),第二次是清除上次画的内容。这个相信大家没意见。偶数就没内容,奇数就能画出内容----黑色矩形边框。

问题产生:
WM_LBUTTONDOWN中出现了一次,也是第一次出现,所以为画黑色矩形边框,然后WM_MOUSEMOVE却出现了2次,头一次是清除,第二次就是画黑色矩形边框,没有问题吧。因为是3次嘛,上面说了,奇数能画内容的。

当我把WM_LBUTTONDOWN中的DrawBoxOutline 去掉,程序依然没问题能够在鼠标移动过程中出现黑色矩形边框,对于这点我想不明白,这里已经成了偶数2了,为什么依然能实现鼠标移动过程中画出黑色矩形边框?对于这点匪夷所思。

补充一点:
上面代码中我故意注释掉了2行,大家把那两行注释去掉,就能发现鼠标移动过程中将不会在出现黑色矩形边框,原因相信有人能叙述出来。。。。。。。。。。哈哈,很抱歉,此人并非是我。。。。。。(VC6.0)
...全文
224 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
yiruirui0507 2011-01-26
  • 打赏
  • 举报
回复
大体上我认为是rectangle在WM_LBUTTONDOWN消息中没发挥任何作用,因为点相同的缘故,如果这样理解的话,下面的问题也就解决了。但始终认为既然作者这么写,并且这本书延续到了第五章,应该不至于放置这样的“垃圾代码”吧。
yiruirui0507 2011-01-26
  • 打赏
  • 举报
回复
针对上面这个问题反复思考,又找到了一个疑问,关于Rectangle函数的
在WM_LBUTTONDOWN中有句这样的代码
ptBeg.x = ptEnd.x = LOWORD (lParam) ;
ptBeg.y = ptEnd.y = HIWORD (lParam) ;

大家都看到了,这里坐标完全相同,为什么Rectangle还能画矩形操作?这里很显然已经是个点了,我用
GetLastError跟踪发现返回值为0,表示操作成功。
奇怪了,坐标相同又画不出来矩形表示返回成功?神马意思?就算返回成功,那这里也该画一个点啊,但是调试又发现什么都没画,所以希望大家帮忙解除一下小弟对这个函数的困惑。先谢谢。
sendwb 2011-01-26
  • 打赏
  • 举报
回复
另外值得注意的一点,你在处理PRINT消息时也设置了SETROP2这是个很危险的做法,因为PRINT消息会一直处理,这时绘制状态就没办法确定了。
sendwb 2011-01-26
  • 打赏
  • 举报
回复
问题出在你的WM_MOUSEMOVE 你在处理鼠标移动消息时调用了两次,而你在鼠标按下时也调用了一次,所以在处理WM_MOUSEMOVE 时仍然是一个奇数状态,,即是在鼠标左键按下时开始开始绘制,而在鼠标移动时,调用第一个DrawBoxOutline 擦除,调用第二次DrawBoxOutline 就仍然绘制。
yiruirui0507 2011-01-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 sendwb 的回复:]
问题出在你的WM_MOUSEMOVE 你在处理鼠标移动消息时调用了两次,而你在鼠标按下时也调用了一次,所以在处理WM_MOUSEMOVE 时仍然是一个奇数状态,,即是在鼠标左键按下时开始开始绘制,而在鼠标移动时,调用第一个DrawBoxOutline 擦除,调用第二次DrawBoxOutline 就仍然绘制。
[/Quote]
感谢回答,毕竟你是NO1,嘿嘿,不过你好像没看清楚我的问题,回答的内容是对的,我是说把WM_LBUTTONDOWN中的那次函数调用给去掉却仍然能实现,偶数了也行,为何?

16,472

社区成员

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

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

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