8

説明:

右から左への読み取りモード (RTL) のツリー ビューを使用して、クリック座標だけを知っているクリックされたノードを取得する方法は? 以下は、RTL 表示を使用するようにツリー ビューを作成し、問題を確認できるクリック ハンドラーを含むクラスを挿入したものです。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, CommCtrl;

type
  TTreeView = class(ComCtrls.TTreeView)
  protected
    procedure CNNotify(var Msg: TWMNotify); message CN_NOTIFY;
    procedure CreateParams(var Params: TCreateParams); override;
  end;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TTreeView }

procedure TTreeView.CNNotify(var Msg: TWMNotify);
var
  Node: TTreeNode;
  Point: TPoint;
begin
  inherited;
  if Msg.NMHdr.code = NM_CLICK then
  begin
    Point := ScreenToClient(Mouse.CursorPos);
    Node := GetNodeAt(Point.X, Point.Y);
    if Assigned(Node) then
      ShowMessage('This message never shows...');
  end;
end;

procedure TTreeView.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.Style := Params.Style or TVS_RTLREADING;
  Params.ExStyle := Params.ExStyle or WS_EX_LAYOUTRTL or WS_EX_RIGHT;
end;

{ TForm1 }    

procedure TForm1.FormCreate(Sender: TObject);
var
  Node: TTreeNode;
begin
  Node := TreeView1.Items.AddChild(nil, 'Item 1');
  TreeView1.Items.AddChild(Node, 'SubItem 1');
end;

end.

このコードの問題 (RTL モードでのツリー ビューの場合の方が適切です) は、ノード (または任意の場所) をクリックしても、GetNodeAtメソッドが有効なノードを返さない (常にnil) ことです。Delphi を持っていない人のために、このGetNodeAtメソッドはマクロを内部的に呼び出します。このTreeView_HitTestマクロは、ツリー ビューが RTL モードの場合NULL、項目がないように戻ります。GetCursorPos関数によってコントロールに対して相対的に計算された、関数によって取得された座標をそのマクロに渡していScreenToClientます。

質問:

私の質問は、マウス座標だけを知っているクリックされたノードを取得する方法ですか? RTL モードでツリー ビューを使用してヒット テストを行うにはどうすればよいですか? たとえば、右からマウスの水平位置を計算する必要がありますか?

4

1 に答える 1

13

ScreenToClientドキュメントから:

ミラーリングの状況、つまり左から右へのレイアウトから右から左へのレイアウトに変更する場合は、ScreenToClientを使用しないでください。代わりに、を使用してMapWindowPointsください。詳細については、ウィンドウ機能の「ウィンドウのレイアウトとミラーリング」を参照してください。

修正されたコードは次のようになります。

  ..
  Point := Mouse.CursorPos;
  MapWindowPoints(0, Handle, Point, 1);
  Node := GetNodeAt(Point.X, Point.Y);
  ..

参照:ウィンドウのレイアウトとミラーリング

于 2012-10-22T20:27:48.727 に答える