6

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

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

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

在这种情况下,有什么想法可以减少 CPU 使用率吗?

4

6 回答 6

4

您可以创建一个 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;
于 2009-03-25T16:55:22.117 回答
3
  1. 它与鼠标移动本身无关。
  2. 除非这是您的意图,否则您将 X、Y 与 Top、Left 不匹配。顶部是 Y 坐标,左侧是 X 坐标。
  3. 问题是AnotherComponent 的实际移动。

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

于 2009-03-25T18:57:20.483 回答
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 行),没有计时器,对我来说效果很好......

于 2009-03-26T08:39:12.910 回答
1

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

于 2009-03-26T06:45:26.647 回答
0

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

于 2009-03-25T16:59:18.643 回答
0

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

来自 MSDN:

当用户移动鼠标,或者按下或释放鼠标按钮时,鼠标会产生一个输入事件。系统将鼠标输入事件转换为消息并将它们发送到相应线程的消息队列中。当鼠标消息的发布速度快于线程处理它们的速度时,系统会丢弃除最近的鼠标消息之外的所有消息。

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

于 2009-03-25T17:22:14.767 回答