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 回答