delphi – 如何在将屏幕对象处理到DrawFocusRect时消除屏幕闪烁
我试图在我多年前开发的Apprehend Screen Capture Component中围绕选定的屏幕对象绘制一个聚焦矩形.我可以通过Handles:= WindowFromPoint(P)获取光标下对象的句柄来绘制DrawFocusRect;但这要求我隐藏然后显示自己的工作,否则返回自我的句柄.
不幸的是,当我隐藏并显示表单时,它会在隐藏和显示表单时导致闪烁. 我可以毫无问题地获得所选对象的位图,只是绘制选定的对象让我疯狂. 有没有人有任何建议围绕选定的对象绘制一个FocusedRect,所以没有闪烁?如果表单位于屏幕顶部,是否有任何API可以获取屏幕句柄? 我尝试使用Handles:= WindowFromDC(ScreenDC),所以我不必隐藏和显示表单,但WindowFromDC仍然返回表单而不是屏幕. TCaptureObjectForm是透明的,位于屏幕上方.我需要组件中的TCaptureObjectForm. // FormMouseMove事件 – 已添加08/2/2011 procedure TCaptureObjectForm.FormMouseMove( Sender: TObject; Shift: TShiftState; X,Y: Integer ); const crHand = -18; var P: TPoint; Handles: HWND; Rect: TRect; ScreenDC: HDC; begin // hide the TCaptureObjectForm form so the screen is found by WindowFromPoint Self.Hide; // get the object on the screen GetCursorPos( P ); Handles := WindowFromPoint( P ); // tried this but it returns self.handle rather than the screen handle //ScreenDC := GetDC( 0 ); //Handles := WindowFromDC(ScreenDC); //ReleaseDC( 0,ScreenDC ); // restore the TCaptureObjectForm Self.Show; // get object rect GetWindowRect( Handles,Rect ); // draw a rect to show it is focused Self.Canvas.DrawFocusRect( Rect ); end; 解决方法
This article是Microsoft的Visual Basic中的一个示例,它执行与您所需的非常相似的操作.
他们采取以下方法: >在Form_MouseDown中捕获鼠标. 他们直接在他们选择的窗口中绘制.我不认为使用透明窗口方法可以避免所有闪烁. 该代码示例似乎不完整且效果不佳,因此我对其进行了修改(并转换为Delphi): // Not global variables,but private form ones var HwndLastTracked: HWND; CapturedMouse: boolean; procedure InvertTracker(hwndWindow: HWND); var rc: TRect; dc: HDC; pen,oldPen: HPEN; oldBrush: HBRUSH; style,exStyle: longint; cx,cy: integer; begin GetWindowRect(hwndWindow,rc); // Window coordinates of the origin (top-left corner) of a window is (0,0) OffsetRect(rc,-rc.Left,-rc.Top); // DC returned by GetWindowDC covers the full window area,but in Windows // Vista/7 it seems to be clipped excluding the nonclient region,due to // DWM handling nonclient drawing,so it doesn't allow painting over it. // Thus we need to skip this nonclient area and that is why I adjust the // window rect to match the client area. Using GetClientRect instead of // GetWindowRect is not suitable as excludes scroll bars and child // parts drawed in WM_NCPAINT,such as Windows' WS_EXEDGEs and Delphi's // bevels. style := GetWindowLong(hwndWindow,GWL_STYLE); exStyle := GetWindowLong(hwndWindow,GWL_EXSTYLE); if style and WS_CAPTION <> 0 then begin if exStyle and WS_EX_TOOLWINDOW <> 0 then cy := GetSystemMetrics(SM_CYSMCAPTION) else cy := GetSystemMetrics(SM_CYCAPTION); // discard area covered by caption Inc(rc.Top,cy); end; if style and WS_THICKFRAME <> 0 then begin cx := GetSystemMetrics(SM_CXFRAME); cy := GetSystemMetrics(SM_CYFRAME); end else if style and WS_DLGFRAME <> 0 then begin cx := GetSystemMetrics(SM_CXDLGFRAME); cy := GetSystemMetrics(SM_CYDLGFRAME); end else if style and WS_BORDER <> 0 then begin cx := GetSystemMetrics(SM_CXBORDER); cy := GetSystemMetrics(SM_CYBORDER); end else begin cx := 0; cy := 0; end; if (cx <> 0) or (cy <> 0) then begin // discard area covered by borders OffsetRect(rc,cx,cy); Dec(rc.Right,cx*2); Dec(rc.Bottom,cy*2); end; // Windows API functions don't raise exceptions,so I don't use try-finally dc := GetWindowDC(hwndWindow); // Option 1: focused rect //DrawFocusRect(dc,rc); // Option 2: inverted thick border SetROP2(dc,R2_NOT); pen := CreatePen(PS_INSIDEFRAME,3 * GetSystemMetrics(SM_CXBORDER),0); oldPen := SelectObject(dc,pen); oldBrush := SelectObject(dc,GetStockObject(NULL_BRUSH)); Rectangle(dc,rc.Left,rc.Top,rc.Right,rc.Bottom); SelectObject(dc,oldBrush); SelectObject(dc,oldPen); DeleteObject(pen); // End option 2 ReleaseDC(hwndWindow,dc); end; procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer); begin if SetCapture(Handle) <> 0 then begin CapturedMouse := true; HwndLastTracked := 0; Screen.Cursor := crCross; end; end; procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer); var hwndCaptured: HWND; begin if CapturedMouse then begin hwndCaptured := WindowFromPoint(ClientToScreen(Point(X,Y))); // Uncomment this for track root windows instead of childs //hwndCaptured := GetAncestor(hwndCaptured,GA_ROOT); if hwndCaptured <> HwndLastTracked then begin if HwndLastTracked <> 0 then InvertTracker(HwndLastTracked); InvertTracker(hwndCaptured); HwndLastTracked := hwndCaptured; end; end; end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer); begin if CapturedMouse then begin ReleaseCapture; CapturedMouse := false; if HwndLastTracked <> 0 then begin InvertTracker(HwndLastTracked); HwndLastTracked := 0; end; Screen.Cursor := crDefault; end; end; 以下是Microsoft在Visual Studio的Spy中如何使用此技术的屏幕截图.红色的气球和文字都是我的! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |