4

TWinControl の MouseMove イベント内で WindowFromPoint を呼び出すと、WindowFromPoint に渡されたポイントで MouseOver イベントが発生します。これは VCL のバグですか? 回避策があるかどうか知っている人はいますか?

ここに画像の説明を入力

デモコードは次のとおりです。

unit Unit7;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm7 = class(TForm)
    Button1: TButton;
    procedure Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form7: TForm7;

implementation

{$R *.dfm}

procedure TForm7.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  WindowFromPoint(Point(Mouse.CursorPos.X, Mouse.CursorPos.Y - 40));
end;

end.

DFM:

object Form7: TForm7
  Left = 0
  Top = 0
  Caption = 'Form7'
  ClientHeight = 40
  ClientWidth = 116
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 24
    Top = 7
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnMouseMove = Button1MouseMove
  end
end

Windows 7 Pro 64bit で Delphi XE2 を使用しています。Delphi 7でも再現できます。

4

1 に答える 1

4

これを最も単純な C++ アプリケーションでテストしたところ、同じ動作が観察されました。これは VCL のバグではありません (David がコメントで述べたように)。ところで、マウスの動きとは関係ありませんWindowFromPoint。キャプション ボタンの座標を渡すたびに、特異性が発生します。また、関数を呼び出すスレッドに属するウィンドウでのみ発生します。

したがって、回避策としてWindowFromPoint、スレッドから呼び出すことができます。以下の簡単な例は、コードが終了するのを待っているため、実際にはバックグラウンド スレッドではありません。

type
  TGetWndThread = class(TThread)
  private
    FPoint: TPoint;
  protected
    procedure Execute; override;
    constructor Create(AOwner: TComponent; Point: TPoint);
  end;

constructor TGetWndThread.Create(AOwner: TComponent; Point: TPoint);
begin
  FPoint := Point;
  inherited Create;
end;

procedure TGetWndThread.Execute;
begin
  ReturnValue := WindowFromPoint(FPoint);
end;

..

var
  Wnd: HWND;
  Thr: TGetWndThread;
begin
  Thr := TGetWndThread.Create(nil, Point(Mouse.CursorPos.X, Mouse.CursorPos.Y - 40));
  Wnd := Thr.WaitFor;
  Thr.Free;
  .. // use Wnd


バグが表示される条件 (OS、テーマなど) をテストし、不要なオーバーヘッドを回避するためにコードを条件付きにすることは理にかなっています。

于 2012-12-18T23:47:56.977 に答える