我需要能够在同一时刻拦截平板电脑上的多个分接头的代码。在关于如何在同一时刻(不可能)处理多个OnMouseDown的previous question中,提供了link来回答关于如何处理Delphi-Android中的多点触控点击的问题。但是,此代码返回屏幕坐标中的(x,y)位置,我不知道如何将这些位置转换为特定控件的本地坐标。 Delphi documentation引用了ScreenToClient函数但只将屏幕坐标转换为表格坐标,这在Android中几乎没用(文档是关于XE2的,但该函数仍然存在于XE5中,但该函数已从FMX中删除。 FMX.Form的平台)。
有没有一种简单的方法可以将屏幕坐标转换为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 //
这段代码实际上非常不整洁,因为它假定Parent控件将Application.MainForm作为其父级,但不一定是这种情况。另一个观察结果是,在Y位置,水龙头可能仍然略有错误。出于这个原因,我想将屏幕坐标直接传输到控件的坐标。
修改2
我尝试使用@Sentient建议的每个键控制的IsMouseOver检查,但奇怪的是,只有在处理MouseUp事件时才会产生true。
答案 0 :(得分: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;