Как уменьшить нагрузку на процессор при перемещении компонента в событии OnMouseMove в Delphi 7? - PullRequest
6 голосов
/ 25 марта 2009

В приложении Delphi 7 я хочу переместить компонент, следуя за мышью. Я делаю что-то вроде этого:

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

Когда я перемещаю мышь, загрузка процессора для основного ядра возрастает до 100% на последнем ПК.

Любая идея или галочка, чтобы уменьшить использование процессора в этом случае?

Ответы [ 6 ]

4 голосов
/ 25 марта 2009

Вы можете создать 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;
3 голосов
/ 26 марта 2009

Наконец, я изменил свой код для этого:

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 строки), таймера нет, у меня хорошо работает ...

3 голосов
/ 25 марта 2009
  1. Это не имеет никакого отношения к самому движению мыши.
  2. Если это не то, что вы хотели, вы не соответствуете X, Y с Top, Left. Сверху - координата Y, а слева - X.
  3. Проблема заключается в фактическом перемещении AnotherComponent.

Чтобы попытаться понять это, я предлагаю вам написать процедуру TestMove, которая автоматически перемещает ваш AnotherComponent с настраиваемыми повторениями / задержками для мониторинга ЦП.
Могу поспорить, что это вызывает дорогостоящие перекраски или некоторые другие интенсивные вычисления процессора.
Поэтому внимательно изучите, если у вас есть какой-либо обработчик событий для этого компонента, а затем переходите к унаследованному поведению ...

1 голос
/ 26 марта 2009

Возможно, вместо перемещения самого компонента вы перемещаете «тень» и перемещаете компонент только после того, как пользователь отпускает кнопку мыши. Вроде как drag & drop.

0 голосов
/ 25 марта 2009

Все, что связано с событием перемещения мыши, будет вызываться очень часто, поскольку мыши являются устройством ввода с высоким разрешением. Я бы не стал беспокоиться об использовании процессора, потому что ваш обработчик запускается только настолько быстро, насколько это возможно, в зависимости от загруженности системы. Другими словами, это только максимальная загрузка процессора, потому что больше ничего нет.

Из MSDN:

Мышь генерирует событие ввода когда пользователь перемещает мышь, или нажимает или отпускает кнопку мыши. Система преобразует события ввода мыши в сообщения и отправляет их на очередь сообщений соответствующего потока. Когда сообщения мыши публикуются быстрее чем поток может их обработать, тем система отбрасывает все, кроме самого недавнее сообщение мыши.

Теперь могут быть некоторые исключения из этого. Вы можете провести некоторое тестирование, чтобы быть уверенным, выполнив какое-то другое интенсивное процессирование и посмотреть, насколько сильно на него воздействует движение мыши.

0 голосов
/ 25 марта 2009

Это не может быть самому движению, которое нуждается в такой большой вычислительной мощности процессора, скорее всего, движение заставляет компонент каким-то образом перерисовываться. Можете ли вы избежать того, что AnotherComponent перерисовывается при каждом движении? В этом нет необходимости, если только это не контейнер с фильмом.

...