如何将屏幕坐标转换为控制坐标

Arn*_*old 5 delphi android delphi-xe5

我需要能够在同一时刻拦截平板电脑上几个水龙头的代码.在之前关于如何在同一时刻(不可能)处理多个OnMouseDown的问题中,提供了一个链接,该链接回答了如何在Delphi-Android中处理多点触控点击的问题.但是,此代码返回屏幕坐标中的(x,y)位置,我不知道如何将这些位置转换为特定控件的本地坐标.Delphi 文档引用了ScreenToClient函数,但只将屏幕坐标转换为表格坐标,这在Android中几乎没用(文档是关于XE2的,但该函数仍然存在于XE5中,但该函数已从FMX.Platform移除到FMX.形成).

有没有一种简单的方法可以将屏幕坐标转换为FMX中的TControl坐标,就像在VCL中一样?当然,我可以"取消父级"一个控件,记下它的左上角坐标,并为每个父级执行此操作,直到到达基本形式,但这非常繁琐.

编辑1

我目前的方法是获取TControl(一个TPanel)的顶部(x,y)坐标,它是要点击的控件(实际上是TRectangle)的父级,并添加这些以检查点击是否在该矩形内.请参阅下面的示例代码

procedure TKeyBoard.process_touch (Event: TTouchEvent; status_byte: Int32);
var
  key: TKey;
  p, q: TPointF;
  i: Integer;
  x, y: single;
begin
// Check whether at least one event is present. If so, i points to the last event
   i := Length (Event.Points) - 1;
   if i < 0 then Exit;

// Get (x, y) coordinates from event. It's in screen coordinates
   x := Event.Points [i].Position.X;
   y := Event.Points [i].Position.Y;

// FControl is a reference to the panel holding the keys
// Find its rectangle position and convert to screen coordinates
   p := TPointF.Create (FControl.Position.X, FControl.Position.Y);
   q := TPointF.Create (p.X + FControl.Width, p.Y + FControl.Height);
   p := Application.MainForm.ClientToScreen (p);
   q := Application.MainForm.ClientToScreen (q);

   logd ('control [%.0f %.0f - %.0f, %.0f]', [FControl.Position.X, FControl.Position.Y, FControl.Width, FControl.Height]);
   logd ('to screen [%.0f %.0f - %.0f, %.0f]', [p.X, p.Y, q.X, q.Y]);

// Determine whether a black key has been pressed
   for i := Low (Fkeys) to High (FKeys) do
   begin
      if not cOctave_Major [i mod nOctave] then
      begin
         key := FKeys [i];

         logd ('%d (%.0f, %.0f) - (%.0f, %.0f) (%.0f, %.0f)', [i, x, y,
                  key.Position.X + p.X,             key.Position.Y + p.Y,
                  key.Position.X + P.X + Key.Width, key.Position.Y + p.Y + key.Height]);

         if (x >= key.Position.X + p.X) and (x <= key.Position.X + p.X + Key.Width) and
            (y >= key.Position.Y + p.Y) and (y <= key.Position.Y + p.Y + key.Height)
            then break;
         key := nil;
      end; // if
   end; // for

// if not, check whether a white key has been pressed
   if key = nil then
   begin
      logd ('Major');
      for i := Low (Fkeys) to High (FKeys) do
      begin
         if cOctave_Major [i mod nOctave] then
         begin
            key := FKeys [i];

            logd ('%d (%.0f, %.0f) - (%.0f, %.0f) (%.0f, %.0f)', [i, x, y,
                  key.Position.X + p.X,             key.Position.Y + p.Y,
                  key.Position.X + P.X + Key.Width, key.Position.Y + p.Y + key.Height]);

            if (x >= key.Position.X + p.X) and (x <= key.Position.X + p.X + Key.Width) and
               (y >= key.Position.Y + p.Y) and (y <= key.Position.Y + p.Y + key.Height)
               then break;
            key := nil;
         end; // if
      end; // for
   end; // if


   if key <> nil
      then putShort (status_byte, key.Note, 127);
   if key <> nil
      then logd (' found %s', [key.Text.Text]);
end; // process_touch //
Run Code Online (Sandbox Code Playgroud)

这段代码实际上非常不整洁,因为它假定Parent控件具有Application.MainForm作为其父级,而不一定是这种情况.另一个观察结果是,在Y位置,水龙头可能仍然略有错误.出于这个原因,我想将屏幕坐标直接传输到控件的坐标.

编辑2

我尝试使用@Sentient建议的每个键控制的IsMouseOver检查,但奇怪的是,只有在处理MouseUp事件时才产生true.

Run*_*ner 9

我是您正在使用的多点触控代码的作者.当我看到你在坐标上挣扎时,我看了可以做什么并更新了代码,所以它现在为你提供了触摸控件和相对坐标.此外,如果你想知道如何简单.

关于它的博客文章在这里:

http://www.cromis.net/blog/2014/02/multi-touch-touched-control-and-relative-coordinates/

解决它的代码如下所示:

  if Screen.ActiveForm <> nil then
  begin
    for I := 0 to Length(Event.Points) - 1 do
    begin
      Control := Screen.ActiveForm.ObjectAtPoint(Event.Points[I].Position);

      if Control <> nil then
      begin
        Event.Points[I].Control := Control as TFmxObject;
        Event.Points[I].RelPosition := Control.ScreenToLocal(Event.Points[I].Position);
      end
      else
      begin
        Event.Points[I].Control := Screen.ActiveForm;
        Event.Points[I].RelPosition := Screen.ActiveForm.ScreenToClient(Event.Points[I].Position);
      end;
    end;
  end;
Run Code Online (Sandbox Code Playgroud)

  • “我是作者......”总是一个很好的答案。+1。有趣的相关系列博客文章也是。 (2认同)