How to reduce CPU usage when moving a component in a OnMouseMove event in Delphi 7?
Asked Answered
V

6

6

In a Delphi 7 application, I want to move a component following the mouse. I'm doing something like this:

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

When I move the mouse the CPU usage for the main core goes up to 100% on a recent PC.

Any idea or tick to reduce the CPU usage in this case ?

Voncile answered 25/3, 2009 at 16:51 Comment(1)
Could you please add whether the component and the control below it are windowed controls or not? Do they have complicated painting code?Berar
V
4

Finally I've change my code for this one:

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;

Really easy to implement (2 lines added), no timer, works well for me...

Voncile answered 26/3, 2009 at 8:39 Comment(2)
Check your X & Y there as Left is X, Top is Y. If this is working for you, then fine, but it seems wrong.Ursuline
I like this better than my solution :)Hospitalization
H
4

You could create a TTimer that polls the current mouse position every 0.10 seconds or so, then positions "AnotherComponent" according to the current mouse position.

Then you wouldn't fire your event for every pixel of mouse movement- you won't need any OnMouseMove event on your controlling component at all.

On my computer, this basically has no performance impact at all.

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;
Hospitalization answered 25/3, 2009 at 16:55 Comment(0)
V
4

Finally I've change my code for this one:

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;

Really easy to implement (2 lines added), no timer, works well for me...

Voncile answered 26/3, 2009 at 8:39 Comment(2)
Check your X & Y there as Left is X, Top is Y. If this is working for you, then fine, but it seems wrong.Ursuline
I like this better than my solution :)Hospitalization
R
3
  1. It has nothing to do with the Mouse Move itself.
  2. Unless it's what you intended, you are mismatching X, Y with Top, Left. Top is the Y coord and Left the X one.
  3. The problem is the actual moving of AnotherComponent.

To try and understand it, I suggest that you write a TestMove routine that moves your AnotherComponent automatically with adjustable repetition/delays to monitor the CPU.
I bet it triggers a costly repaint or some other CPU intensive calculation.
So Examine closely if you have any event handler on this component first, then go with the inherited behavior...

Rebeca answered 25/3, 2009 at 18:57 Comment(0)
C
1

Maybe, instead of moving the component itself you move a 'shadow' and only move the component once the user lets the mousebutton go. Sort of like drag&drop.

Catechist answered 26/3, 2009 at 6:45 Comment(0)
C
0

It can't be the move itself that needs so much cpu power, most probably the move causes the component to redraw itself somehow. Can you avoid that AnotherComponent is redrawn on each move? It should not be necessary, unless it is a movie container.

Christiano answered 25/3, 2009 at 16:59 Comment(0)
A
0

Anything tied to the mouse move event will be called very frequently as mice are a high resolution input device. I wouldn't worry about the cpu usage though because your handler only gets fired as fast as possible based on how busy the system is. In other words, it's only maxing the CPU because nothing else is.

From MSDN:

The mouse generates an input event when the user moves the mouse, or presses or releases a mouse button. The system converts mouse input events into messages and posts them to the appropriate thread's message queue. When mouse messages are posted faster than a thread can process them, the system discards all but the most recent mouse message.

Now there may be some exceptions to this. You could do some testing to be sure by running some other processing intensive activity and see how much the mouse move stuff impacts it.

Alewife answered 25/3, 2009 at 17:22 Comment(3)
Down votes without an explanation are not as constructive as they could be. If you can identify something wrong, please let us know. I will happily make a correction to my answer.Alewife
I did not downvote you, however your POV is not multi-tasking-friendly. The GUI thread will have normal priority, so it will completely starve all threads with lower priority, and take away cycles from threads with same priority. Optimizing for lowest CPU load is important, even if unfashionable.Berar
That may be true as a general rule but this is a GUI process. Interaction with the user generally always takes precedence as responsiveness is a priority. It looks like the author is trying to animate a mouse drag operation. Wouldn't want that jumping periodically out of sync with the mouse.Alewife

© 2022 - 2024 — McMap. All rights reserved.