如何显示弹出窗口动画帧(从网格单元格矩形开始)

时间:2014-12-08 18:18:17

标签: windows delphi animation rect

我正在使用BDS 2007 ......

当用户在我们的应用程序中双击网格单元格时,我们会在网格上显示一个模态窗口。我开发了下面的例程,在网格上绘制一个动画帧。它通过在窗口显示之前逐步绘制和擦除帧来进行放大(非常类似于Windows UI动画)。窗口关闭后,再次调用相同的例程(使用bExpand = False),以使窗口的UI效果重新进入网格单元格。

此例程在Windows XP中运行良好但在启用Aero时行为不当(在Windows 7 中没有 Aero的情况下正常工作)。动画帧重绘得很慢......即使我注释掉DelayMSecs行(这只是一个重复调用Sleep(0)的循环,直到iDelay毫秒数已经过去)。

当再次调用例程时(窗口关闭后)它同样慢,加上在屏幕上留下一个框架,再加上一个(现已关闭的)窗口留下的鬼图像,基本上是alpha混合的网格的正常显示内容。

大多数例程的代码计算变化的矩形大小。实际抽奖只有三行。擦除动画rect:

          ScreenCanvas.Rectangle( r );               //draw frame
          SysStuff.DelayMSecs( iDelay );             //
          ScreenCanvas.Rectangle( r );               //pmXOR pen ...erase frame

关于为什么在Aero下这么慢,或者我需要改变什么的想法?

procedure T_fmExplore.AnimateRects(ASourceRect, ADestRect: TRect; bExpand:
    boolean; bAdjustSourceForFrame: boolean = True);
{ Draw animation frames in steps, for transition from ASourceRect to ADestRect.
    bExpand:  determines whether the animation rect is expanding or contracting.
    bAdjustSourceForFrame:  resize the animation rect smaller for the window frame. }
const
  MINSTEPS = 10;               //Min redraws of the animation rect (frame)
  MAXSTEPS = 20;               //30 was too many, too slow
  MAXDELAY = 100;              //Delay between drawing each rect frame
  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;
  TgtWidth, TgtHt: Integer;
  iTemp: Integer;
  iDelay: integer;
  r : TRect;                    //Animation frame's rect
  ScreenCanvas: TCanvas;
begin
  r := ASourceRect;
  TgtWidth :=   ADestRect.Right - ADestRect.Left;         //Target rect's Width
  TgtHt :=      ADestRect.Bottom - ADestRect.Top;         //Target rect's Height
      //Initially Deltas hold total chg in Width & Height
  DeltaWidth := TgtWidth - (r.Right - r.Left);            //TgtWidth - old width
  DeltaHt :=    TgtHt - (r.Bottom - r.Top);
      //For smooth animation we adjust number of iSteps & Delay relative to the window area.
      //Larger window = more iSteps and shorter Delay between drawing each step.
  iSteps := Max( DeltaWidth * DeltaHt div 6500, MINSTEPS );
  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;   //Do NOT use clBlack with pmXOR mode: with (r=0, g=0, b=0) there are no bytes to XOR.
        Pen.Mode := pmXOR;      //MUST use pmXOR pen, so 2nd Rectangle call (see below) erases what we drew.
        Pen.Style := psSolid;
        Pen.Width := 3;         //Thin line.  Was: Pen.Width := GetSystemMetrics(SM_CXFRAME);
        Brush.Style := bsClear;
        if bAdjustSourceForFrame then
          InflateRect(ASourceRect, -Pen.Width, -Pen.Width);
        repeat
          iTemp := (r.Bottom - r.Top) + DeltaHt;        //Height
          if (bExpand and (iTemp > TgtHt)) or (not bExpand and (iTemp < TgtHt)) then begin
            r.Top := ADestRect.Top;
            r.Bottom := Top + TgtHt;
          end else begin
            r.Top := r.Top + DeltaTop;            //Assign Top first...Bottom is calc'd from it
            r.Bottom := r.Top + iTemp;
          end;

          iTemp := (r.Right - r.Left) + DeltaWidth;     //Width
          if (bExpand and (iTemp > TgtWidth)) or (not bExpand and (iTemp < TgtWidth)) then begin
            r.Left := r.Left + DeltaLeft;
            r.Right := r.Left + TgtWidth;
          end else begin
            r.Left := r.Left + DeltaLeft;         //Assign Left first...Right is calc'd from it
            r.Right := r.Left + iTemp;
          end;

          ScreenCanvas.Rectangle( r );               //draw frame
          SysStuff.DelayMSecs( iDelay );             //
          ScreenCanvas.Rectangle( r );               //pmXOR pen ...erase frame

        until (r.Right - r.Left = TgtWidth) and (r.Bottom - r.Top = TgtHt);
      end;
    finally
      ReleaseDC( 0, ScreenCanvas.Handle );
      ScreenCanvas.Handle := 0;
    end;
  finally
    ScreenCanvas.Free;
  end;
end;

0 个答案:

没有答案