我开发了以下AnimateRects()方法在Windows桌面上绘制动画矩形。我使用它来动画显示模态窗体,使它看起来像是从一个网格单元“长大”的。为什么带有pmXOR笔的TCanvas.Rectangle()只能“有时”工作?
在窗体显示之前,我使用bExpand参数= True调用该方法一次。然后,当用户关闭窗体时,我再次调用窗体,但使用bExpand = False,以将窗体“折叠”显示到网格单元格中。
的问题是与bExpand =假的情况下...在循环的第一次迭代中,第一调用矩形(R)绘制预期的长方形,但它仿佛第二调用矩形(r)从未被调用 - 第一个矩形永远不会被异或。因此,在绘制了“折叠”矩形序列之后,我将屏幕上的第一个矩形作为工件。
任何想法我做错了什么?
const
MSECS_PER_DAY = 24.0 * 60.0 * 60.0 * 1000;
procedure DelayMSecs(msecs: Word);
var
Later: TDateTime;
begin
Later := Now + (msecs/MSECS_PER_DAY);
while Now < Later do begin
Application.ProcessMessages;
sleep(0); //give up remainder of our time slice
end;
end;
procedure T_fmExplore.AnimateRects(ASourceRect, ADestRect: TRect; bExpand:
boolean; bAdjustSourceForFrame: boolean = True);
const
MINSTEPS = 10;
MAXSTEPS = 30;
MAXDELAY = 180; //150 - 200 is about right
MINDELAY = 1;
var
iSteps: integer;
DeltaHt: Integer; //Rect size chg for each redraw of animation window
DeltaWidth: Integer;
DeltaTop : integer; //Origin change for each redraw
DeltaLeft : integer;
NewWidth, NewHt: Integer;
iTemp: Integer;
iDelay: integer;
r : Trect;
ScreenCanvas: TCanvas;
begin
r := ASourceRect;
with r do begin
NewWidth := ADestRect.Right - ADestRect.Left; //Target rect's Width
NewHt := ADestRect.Bottom - ADestRect.Top; //Target rect's Height
//Temporarily, Deltas hold the total chg in Width & Height
DeltaWidth := NewWidth - (Right - Left); //NewWidth - old width
DeltaHt := NewHt - (Bottom - Top);
//With a static number of iSteps, animation was too jerky for large windows.
//So we adjust the number of iSteps & Delay relative to the window area.
iSteps := Max(DeltaWidth * DeltaHt div 6500, MINSTEPS); //eg. 10 iSteps for 250x250 deltas (62500 pixels)
iSteps := Min(iSteps, MAXSTEPS);
//Now convert Deltas to the delta in window rect size
DeltaWidth := DeltaWidth div iSteps;
DeltaHt := DeltaHt div iSteps;
DeltaTop := (ADestRect.Top - ASourceRect.Top) div iSteps;
DeltaLeft := (ADestRect.Left - ASourceRect.Left) div iSteps;
iDelay := Max(MAXDELAY div iSteps, MINDELAY);
ScreenCanvas := TCanvas.Create;
try
ScreenCanvas.Handle := GetDC(0); //Desktop
try
with ScreenCanvas do begin
Pen.Color := clWhite;
Pen.Mode := pmXOR;
Pen.Style := psSolid;
Pen.Width := GetSystemMetrics(SM_CXFRAME);
Brush.Style := bsClear;
if bAdjustSourceForFrame then
InflateRect(ASourceRect, -Pen.Width, -Pen.Width);
repeat
iTemp := (Bottom - Top) + DeltaHt; //Height
if (bExpand and (iTemp > NewHt)) or (not bExpand and (iTemp < NewHt)) then begin
Top := ADestRect.Top;
Bottom := Top + NewHt;
end else begin
Top := Top + DeltaTop; //Assign Top first...Bottom is calc'd from it
Bottom := Top + iTemp;
end;
iTemp := (Right - Left) + DeltaWidth; //Width
if (bExpand and (iTemp > NewWidth)) or (not bExpand and (iTemp < NewWidth)) then begin
Left := Left + DeltaLeft;
Right := Left + NewWidth;
end else begin
Left := Left + DeltaLeft; //Assign Left first...Right is calc'd from it
Right := Left + iTemp;
end;
ScreenCanvas.Rectangle(r);
SysStuff.DelayMSecs(iDelay);
ScreenCanvas.Rectangle(r); //pmXOR pen ...erase ourself
until (Right - Left = NewWidth) and (Bottom - Top = NewHt);
end;
finally
ReleaseDC(0, ScreenCanvas.Handle);
ScreenCanvas.Handle := 0;
end;
finally
ScreenCanvas.Free;
end;
end;
end;
你确定你确实想这么做吗?桌面并不是真的可以吸引你。另外,我用你的DelayMSecs例程把我的鼻子打开。开始“睡眠(0)”不会放弃时间片。如果你的是唯一可运行的线程,那么你将坐在一个小忙环路。 MsgWaitForMultipleObjects有什么问题? –
是的,我真的想这样做 - 这是基于网格应用程序的用户界面的重要组成部分。 (用户需要关于模态对话框的“源”的视觉提示。)对于DelayMSecs,这只是一种东西,随着我将这个例程拼凑在一起并且很快使用。 (首先得到一些有用的东西,然后进行优化。) –
这里的要点是,我试图弄清楚为什么我第二次调用Rectangle()可能只是“什么都不做”。 –