Jump to content
Sign in to follow this  
programmerdelphi2k

Form ObjectAtPoint() does not working or "me" not working :)

Recommended Posts

hello girls and boys,

 

  • RAD 11.2 Alexandria
  • FMX project / 32bits
    • Button1 is on Form1 (directly); 
    • Button1.HitTest = false;

 

I'm having a little problem with something that would, shall we say, not be a problem...

I need to get control over the mouse cursor to perform some extra tasks. However, I'm not understanding why the result is always "nil" for the "ObjectAtPoint" function.


According to the code below, I believe that it should have the intended return, that is, the control "Button1" (IControl representing it)... however, the function is returning "nil"... and, how can be seen on the printscreen, everything goes well until the line number "101",

after it, the "result" is again used to check if "ITSELF" has an "object (children... but does not )" in the given coordinates... this part seems strange to me, however, the code is from Embarcadero... so there was even more doubt!

Quote

function TCommonCustomForm.ObjectAtPoint(AScreenPoint: TPointF): IControl;   // FMX.Forms.pas on RAD 11.2
var
  I: Integer;
begin
  for I := ChildrenCount - 1 downto 0 do
    if Supports(Children, IControl, Result) and Result.GetVisible then
    begin
      Result := Result.ObjectAtPoint(AScreenPoint);
      if Result <> nil then
        Exit;
      end;
  Result := nil;
end;
 

So, if anyone can say something that helps me, I thank you in advance.

 

here my code for tests...

type
  TForm1 = class(TForm)
    Button1: TButton;  // <---- my control into form, "Button1.HitTest := false"
...
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: single);
var
  LPointF: TPointF;
  LIControl: IControl;
begin  
  LPointF          := TPointF.Create(X, Y);
  //
  LIControl := ObjectAtPoint(LPointF);                 = it's nil
  // or
  LIControl := ObjectAtPoint(ClientToScreen(LPointF)); = it's nil
  ...
end;

image.thumb.png.be2d631368a24490da2324f26d6df322.png

 

NOTE: on screenshot is "TEDIT" but in fact is "TButton"... ok == I pasted old printscreen ! SORRY!

 image.thumb.png.f61774bd47ea4de9d6253f5ac492f6d7.png

Edited by programmerdelphi2k

Share this post


Link to post

The problem is: Button1.HitTest := False. This makes it invisible for ObjectAtPoint. See end of 'TControl.ObjectAtPoint' code

  • Like 1

Share this post


Link to post

What do you mean by nope!? Definitely HitTest = False is the reason, why ObjectAtPoint  will not recognize the button. You had to step through all the inherited calls down to TControl. ObjectAtPoint. Here the line

if PointInObject(LP.X, LP.Y) and CheckHitTest(HitTest) then

is the critical part. The first condition is true if over a button, but the second one makes it always fail.

 

Btw: you had to call ObjectAtPoint with Screen coordinates:

LIControl := ObjectAtPoint(ClientToScreen(LPointF));

 

Share this post


Link to post

Then you can't use ObjectAtPoint . You will have to write your own version of it (not that hard, just iterate over all the children and see if position is inside and if it is visible. If so, do the testing on that found control again to get the inner controls of it (if any).

Share this post


Link to post

Now I can find "control" under mouse cursor ....   of course, needs verify if "AControl" is valid / not nil , etc.....

type
  TMyHack = class(TControl);
// to avoid hack the TControl class.... just copy this function and changes last line to "dont verify HitTest property"
function MyObjectAtPoint(const AControl: TControl; AScreenPoint: TPointF): IControl;
var
  // I      : Integer;
  // NewObj : IControl;
  // Control: TControl;
  LP: TPointF;
begin
  if not AControl.ShouldTestMouseHits then
    Exit(nil);
  //
  LP := AScreenPoint;
  //
  if AControl.Scene <> nil then
    LP := AControl.Scene.ScreenToLocal(LP);
  //
  if (AControl.ClipChildren or TMyHack(AControl).SmallSizeControl) and not AControl.PointInObject(LP.X, LP.Y) then
    Exit(nil);
  //
  (* I dont need it, in my usage! I just want first layer!!!
    if AControl.ControlsCount > 0 then
    for I := TMyHack(AControl).GetLastVisibleObjectIndex - 1 downto TMyHack(AControl).GetFirstVisibleObjectIndex do
    begin
    Control := TMyHack(AControl).Controls[I];
    if not TMyHack(Control).GetVisible then
    Continue;
    //
    // pay attention if needs look at "into controls...", then, I should use "MyObjectAtPoint(...') recursivelly"
    // not in "TMyHack(Control).ObjectAtPoint(AScreenPoint);"
    NewObj := TMyHack(Control).ObjectAtPoint(AScreenPoint);
    //
    if NewObj <> nil then
    Exit(NewObj);
    end;
  *)
  result := nil;
  if TMyHack(AControl).PointInObject(LP.X, LP.Y) then // and TMyHack(AControl).CheckHitTest(AControl.HitTest) then
    result := AControl;
end;

 

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
var
  LControl       : IControl;
  LControlAtPoint: IControl;
  LMousePos      : TPointF;
begin
  LMousePos  := Screen.MousePos;
  Memo1.Text := Format('%s -> Mouse cursor at: %f x %f', [TimeToStr(now), LMousePos.X, LMousePos.Y]);
  //
  LControl := Self.ObjectAtPoint(LMousePos);
  //
  if (LControl <> nil) then
    Memo1.Lines.Add('LControl = ' + TControl(LControl).ToString)
    //
  else // trying find TControls (TButton in this case) with "HitTest = false or true"
    begin
      for var I: Integer := 0 to (Self.ChildrenCount - 1) do
        begin
          if not(Self.Children[I] is TButton) then
            Continue;
          //
          if Supports(Children[I], IControl, LControl) and (LControl <> nil) then
            begin
              LControlAtPoint := MyObjectAtPoint(TControl(LControl), LMousePos);
              //
              if (LControlAtPoint <> nil) then
                Memo1.Lines.Add('Control at Point = ' + TControl(LControlAtPoint).ToString);
            end;
        end;
    end;
end;

image.thumb.png.04f9c28c1e144d9de2f7e9688162c2cc.png       :classic_cheerleader:

 

Edited by programmerdelphi2k

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×