How to get a tree view item by the hit test when RTL layout is used?
-
13-07-2021 - |
Вопрос
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 ?
Решение
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