6

Delphi 7 アプリケーションで、マウスに従ってコンポーネントを移動したいと考えています。私はこのようなことをしています:

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

マウスを動かすと、最近の PC でメイン コアの CPU 使用率が 100% まで上がります。

この場合、CPU 使用率を減らすためのアイデアや目盛りはありますか?

4

6 に答える 6

4

現在のマウス位置を約 0.10 秒ごとにポーリングする TTimer を作成し、現在のマウス位置に従って「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の実際の移動です。

それを理解するために、CPUを監視するために調整可能な繰り返し/遅延を使用してAnotherComponentを自動的に移動するTestMoveルーチンを作成することをお勧めします。
コストのかかる再描画やその他の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 に答える