Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a tree view item by the hit test when RTL layout is used?

Description:

Having a tree view in right-to-left reading mode (RTL), how to get node that was clicked knowing just the click coordinates ? Here is an interposed class, that makes the tree view to use the RTL display and that contains a click handler in which you can see the problem:

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.

The problem with this code (or better to say with such tree view in RTL mode) is, that when you click the node (or wherever), the GetNodeAt method never returns a valid node (always nil). For those, who don't have Delphi, the GetNodeAt method internally calls the TreeView_HitTest macro which when the tree view is in RTL mode, returns NULL like there won't be any item. I am passing to that macro the coordinates obtained through the GetCursorPos function calculated relatively to the control by the ScreenToClient function.

Question:

My question is, how to get the clicked node knowing just the mouse coordinates ? How to make a hit test with the tree view in RTL mode ? Should I for instance calculate the mouse horizontal position from right, and if so, how ?

like image 221
TLama Avatar asked Oct 22 '12 18:10

TLama


1 Answers

From ScreenToClient documentation:

Do not use ScreenToClient when in a mirroring situation, that is, when changing from left-to-right layout to right-to-left layout. Instead, use MapWindowPoints. For more information, see "Window Layout and Mirroring" in Window Features.

The corrected code could be like:

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

Also see: Window Layout and Mirroring

like image 172
Sertac Akyuz Avatar answered Oct 04 '22 08:10

Sertac Akyuz