【问题标题】:Double buffering in delphidelphi中的双缓冲
【发布时间】:2012-12-06 17:24:21
【问题描述】:

使用 Delphi XE2 我想让一些按钮在 delphi 应用程序中移动。

我写了这段代码:

procedure TForm1.DoSomething;
var x : integer;
begin    
   for x := 200 downto 139 do begin
       // move two buttons
      Button1.Top := x;
      Button3.Top := x;
       // skip some repaints to reduce flickering
      if (x mod 7 = 1) then begin
          Form1.Repaint;
      Sleep(50);
   end;
end;

不幸的是,运行此程序时它仍然明显闪烁。

这是我的问题: 有什么办法可以让动画流畅(没有任何闪烁)?

编辑: 为使动画更流畅,将 sleep(50) 中的 50 更改为更小的值并删除此行:

if(x mod 7 = 1) then begin

【问题讨论】:

    标签: delphi


    【解决方案1】:

    Form1.DoubleBuffered 设置为True。您可以在代码中执行此操作,但我认为该属性是在 XE2 中发布的,因此您也可以在 Object Inspector 中设置它。

    【讨论】:

    • 如此强大的属性。谢谢,我会在 10 分钟后打勾
    • 是的,但可能会导致令人讨厌的视觉怪癖。
    • @DavidHeffernan 绝对是正确的,如果你能找到一种不使用双缓冲重新绘制无闪烁的方法,那么请尝试这样做。根据我自己的经验,正如 David 指出的那样,双重缓冲通常会导致一些视觉问题,例如按钮周围的暗边等。
    【解决方案2】:

    我发现最好决定您希望运动持续多长时间,而不是使用睡眠程序。这可以更好地适应不同速度的计算机,也可以适应不同的移动距离。如果您希望在屏幕上移动 1 秒,则需要在重绘之间以较小的步长移动,而在屏幕上移动只需 0.5 秒。

    我不记得确切原因,但我们还添加了代码来重新绘制父级。我认为我们的对象在屏幕上移动时会留下鬼影。

    这是我们正在使用的代码。这是在一个组件内部,它可以在屏幕上和屏幕外移动。

    procedure TMyObject.ShiftRight;
    var
      TicksStart: int64;
      StartLeftValue: integer;
      EndLeftValue: integer;
      NewLeftValue: integer;
      LeftValueDif: integer;
      RemainingTicks: int64;
    
    begin
      StartLeftValue := Self.Left;
      EndLeftValue := Self.Left + Self.Width;
      LeftValueDif := EndLeftValue - StartLeftValue;
    
      TicksStart := GetTickCount();
      RemainingTicks := FadeTime;  // Fade Time is a constants that dermines how long the 
                                   // slide off the screen should take
    
      while RemainingTicks > 0 do
      begin
        NewLeftValue := (LeftValueDif * (FadeTime - RemainingTicks)) div FadeTime;
        Self.Left := Max(StartLeftValue, NewLeftValue);
        Self.Parent.Repaint;
        Self.Repaint;
    
        RemainingTicks := FadeTime - int64(GetTickCount - TicksStart);
      end;
    
      if Self.Left < EndLeftValue then
        Self.Left := EndLeftValue;
    
      Self.Parent.Repaint;    
      Self.Repaint;
    end;
    

    【讨论】:

    • 我还注意到睡眠会使不同计算机上的应用程序随机运行。无论如何,感谢您的反馈。
    • 这确实是一种常用的方法:计算对象在当前时间点应该在哪里。不过,我也很想知道这两次重绘。实际上,我想我会选择不在这样的循环中执行此操作,因为它会在循环运行时阻塞应用程序。相反,我想我会使用一个计时器,将循环的内部放入它的 OnTimer 事件中,然后使用 Self.Invalidate 来请求重绘。它将允许快速用户立即继续工作,而无需等待动画完成。
    猜你喜欢
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    • 2010-12-12
    • 2013-04-01
    • 2011-02-20
    • 1970-01-01
    相关资源
    最近更新 更多