【发布时间】:2021-07-21 10:06:20
【问题描述】:
在 Windows 10 的 Delphi 10.4.2 Win32 VCL 应用程序中,我尝试在窗口周围绘制一个框架(-control):
procedure FrameWindow(aHandle: HWND);
var
Rect: TRect;
DC: Winapi.Windows.HDC;
OldPen, Pen: Winapi.Windows.HPEN;
OldBrush, Brush: Winapi.Windows.HBRUSH;
X2, Y2: Integer;
begin
{ Get the target window's rect and DC }
Winapi.Windows.GetWindowRect(aHandle, Rect);
DC := Winapi.Windows.GetWindowDC(aHandle);
{ Set ROP appropriately for highlighting }
Winapi.Windows.SetROP2(DC, R2_NOT);
{ Select brush and pen }
Pen := Winapi.Windows.CreatePen(PS_InsideFrame, 3, 0);
OldPen := Winapi.Windows.SelectObject(DC, Pen);
Brush := Winapi.Windows.GetStockObject(Null_Brush);
OldBrush := Winapi.Windows.SelectObject(DC, Brush);
{ Set dimensions of highlight }
X2 := Rect.Right - Rect.Left;
Y2 := Rect.Bottom - Rect.Top;
{ Draw highlight box }
Rectangle(DC, 0, 0, X2, Y2);
{ Clean up }
SelectObject(DC, OldBrush);
SelectObject(DC, OldPen);
ReleaseDC(aHandle, DC);
{ Do NOT delete the brush, because it was a stock object }
DeleteObject(Pen);
end;
(当使用相同的窗口句柄第二次调用 FrameWindow 过程时,框架将被擦除)。
这适用于窗口上的控件:
当光标下的窗口句柄(Target.WindowHandle)发生变化,需要擦除旧帧时,会定期调用 FrameWindow 过程来绘制新帧:
{ To avoid flickering, remove the old frame ONLY if moved to a new window }
if Target.WindowHandle <> FOldWindowHandle then
begin
if FOldWindowHandle <> 0 then
FrameWindow(FOldWindowHandle); // remove the old frame
if Target.WindowHandle <> 0 then
FrameWindow(Target.WindowHandle); // create new frame
FOldWindowHandle := Target.WindowHandle; // remember new frame
end;
问题 #1:这仅适用于窗口上的控件,而不适用于整个窗口(例如,当鼠标光标位于记事本的标题栏上时),尽管整个窗口的窗口句柄是正确的:没有框架围绕整个窗口绘制。
问题 #2:有时帧已损坏:
问题 #3:如何将框架颜色设置为红色而不是黑色?
如何解决这些问题?
【问题讨论】:
-
您无法可靠地渲染到您不拥有的设备上下文中。
-
@IInspectable 这是什么意思?我怎样才能成为 DC 的所有者?
-
您不能“成为” DC 的所有者。您要么拥有它(例如,因为您创建了它,或者从您拥有的窗口请求了一个),要么不拥有它。没有从后者到前者的去向。如果你想渲染到显示器上,你将不得不创建一个窗口。
-
@IInspectable 所以你说这个过程不能避免重绘问题?
-
不,我是说没有可靠的方法可以将任何渲染到您不拥有的设备上下文中。您无法与 DC 的所有者交流,“嘿,看,我只是为了我的目的而使用了您的一些屏幕空间,您肯定不介意”,因此是没有办法让主人关心的。当它确定需要重绘时,它会继续重绘。
标签: delphi winapi delphi-10.4-sydney