【问题标题】:How to reduce CPU usage when moving a component in a OnMouseMove event in Delphi 7?在 Delphi 7 的 OnMouseMove 事件中移动组件时如何减少 CPU 使用率?
【发布时间】:2010-10-15 12:15:08
【问题描述】:

在 Delphi 7 应用程序中,我想跟随鼠标移动一个组件。我正在做这样的事情:

procedure MyComponent.MouseMove(Sender: TObject;Shift: TShiftState; X, Y: Integer);
begin
  AnotherComponent.Top := X;
  AnotherComponent.Left := Y;
end;

当我移动鼠标时,主内核的 CPU 使用率在最近的 PC 上上升到 100%。

在这种情况下降低 CPU 使用率的任何想法或提示?

【问题讨论】:

  • 能否请您添加组件及其下方的控件是否为窗口控件?他们有复杂的绘画代码吗?

标签: delphi components delphi-7 cpu-usage


【解决方案1】:

您可以创建一个 TTimer,每 0.10 秒左右轮询一次当前鼠标位置,然后根据当前鼠标位置定位“AnotherComponent”。

那么您不会为鼠标移动的每个像素触发事件 - 您的控制组件上根本不需要任何 OnMouseMove 事件。

在我的电脑上,这基本上对性能没有影响。

procedure TForm1.Timer1Timer(Sender: TObject);
var
  pt: TPoint;
begin
  //Is the cursor inside the controlling component?  if so, position some
  //other control based on that mouse position.

  GetCursorPos(pt);
  if MouseWithin(pt.x,pt.y,MyComponent,Form1.Left,Form1.Top) then begin
    //replace with whatever real positioning logic you want
    AnotherComponent.Top := pt.y;
    AnotherComponent.Left := pt.x;
  end;
end;

function TForm1.MouseWithin(mouseX, mouseY: integer;
  const comp: TWinControl; const ParentWindowLeft: integer;
  const ParentWindowTop: integer): boolean;
var
  absoluteCtrlX, absoluteCtrlY: integer;
begin
  //take a control, and the current mouse position.
  //tell me whether the cursor is inside the control.
  //i could infer the parent window left & top by using ParentwindowHandle
  //but I'll just ask the caller to pass them in, instead.

  //get the absolute X & Y positions of the control on the screen
  //needed for easy comparison to mouse position, which will be absolute
  absoluteCtrlX := comp.Left + ParentWindowLeft;
  absoluteCtrlY := comp.Top + ParentWindowTop +
    GetSystemMetrics(SM_CYCAPTION);

  Result := (mouseX >= absoluteCtrlX)
    and (mouseX < absoluteCtrlX + comp.Width)
    and (mouseY >= absoluteCtrlY)
    and (mouseY <= absoluteCtrlY + comp.Height);
end;

【讨论】:

    【解决方案2】:
    1. 它与鼠标移动本身无关。
    2. 除非这是您想要的,否则您将 X、Y 与 Top、Left 不匹配。顶部是 Y 坐标,左侧是 X 坐标。
    3. 问题是AnotherComponent 的实际移动。

    为了尝试理解它,我建议您编写一个 TestMove 例程,该例程自动移动您的 AnotherComponent,并具有可调节的重复/延迟以监控 CPU。
    我敢打赌它会触发代价高昂的重绘或其他一些 CPU 密集型计算。
    因此,请先仔细检查此组件上是否有任何事件处理程序,然后再使用继承的行为...

    【讨论】:

      【解决方案3】:

      最后我改变了我的代码:

      procedure MyComponent.MouseMove(Sender: TObject;Shift: TShiftState; X, Y: Integer);
      begin
        if GetTickCount-LastMoveTick>50 then begin
          AnotherComponent.Top := Y;
          AnotherComponent.Left := X;
          LastMoveTick := GetTickCount;
        end;
      end;
      

      真的很容易实现(添加了 2 行),没有计时器,对我来说效果很好......

      【讨论】:

      • 检查您的 X 和 Y,因为 Left 是 X,Top 是 Y。如果这对您有用,那么很好,但它似乎是错误的。
      • 我比我的解决方案更喜欢这个:)
      【解决方案4】:

      也许,不是移动组件本身,而是移动“阴影”,并且只有在用户放开鼠标按钮时才移动组件。有点像拖放。

      【讨论】:

        【解决方案5】:

        这不可能是移动本身需要如此多的 cpu 能力,很可能是移动导致组件以某种方式重绘自身。 你能避免AnotherComponent在每一步都被重绘吗?应该没有必要,除非它是一个电影容器。

        【讨论】:

          【解决方案6】:

          任何与鼠标移动事件相关的事件都会被频繁调用,因为鼠标是一种高分辨率输入设备。不过,我不会担心 CPU 的使用,因为您的处理程序只会根据系统的繁忙程度尽快触发。换句话说,它只是最大化 CPU,因为没有别的。

          来自 MSDN:

          鼠标产生输入事件 当用户移动鼠标时,或 按下或释放鼠标按钮。 系统转换鼠标输入事件 到消息中并将它们发布到 适当线程的消息队列。 当鼠标消息发布得更快时 比一个线程可以处理它们, 系统丢弃除最 最近的鼠标消息。

          现在可能有一些例外。您可以通过运行其他一些处理密集型活动来进行一些测试,看看鼠标移动对它的影响有多大。

          【讨论】:

          • 在没有解释的情况下投反对票并不像他们可能的那样具有建设性。如果您发现有问题,请告诉我们。我很乐意更正我的答案。
          • 我没有对你投反对票,但是你的 POV 对多任务处理不友好。 GUI 线程将具有正常优先级,因此它将完全饿死所有具有较低优先级的线程,并从具有相同优先级的线程中取出循环。为最低 CPU 负载进行优化很重要,即使不合时宜。
          • 这可能作为一般规则是正确的,但这是一个 GUI 过程。与用户的交互通常总是优先考虑的,因为响应性是优先级。看起来作者正在尝试动画鼠标拖动操作。不希望它周期性地与鼠标不同步。
          猜你喜欢
          • 2016-01-07
          • 2013-12-05
          • 1970-01-01
          • 1970-01-01
          • 2015-08-02
          • 1970-01-01
          • 1970-01-01
          • 2013-06-01
          • 1970-01-01
          相关资源
          最近更新 更多