2014-02-10 5 views
5

Мне нужен код, который способен перехватить несколько нажатий на планшет в тот же момент. В previous question относительно того, как обращаться с несколькими OnMouseDown в тот же момент (не представляется возможным), был предоставлен link, который ответил на вопрос о том, как обрабатывать клики с несколькими касаниями в Delphi-Android. Однако этот код возвращает (x, y) позиции в координатах экрана, и я не знаю, как их перевести в локальные координаты конкретного элемента управления. Delphi documentation относится к функции ScreenToClient, но это только преобразует координаты экрана для формирования координат, что вряд ли полезно в Android (документация о XE2, но функция все еще существует в XE5, но функция была удалена с FMX.Platform на FMX. Форма).Как преобразовать координаты экрана в координаты управления

Есть ли простой способ преобразования координат экрана в координаты TControl в FMX, например, в VCL? Конечно, я могу «де-родитель» контролировать, обозначать его верхние левые координаты и делать это для каждого родителя, пока не достигнет базовой формы, но это довольно утомительно.

Edit 1

Мой текущий подход, чтобы получить вершину (х, у) Координаты TControl (а TPanel), который является родителем для управления должны быть резьбовыми (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 // 

Этот код на самом деле очень неопрятно, потому что она предполагает, что контроль Родитель имеет Application.MainForm в качестве родителя, который не нужно быть. Другое замечание состоит в том, что краны могут все еще быть немного неправильными в Y-положении. По этой причине я хочу передать координаты экрана непосредственно в координаты элемента управления.

Edit 2

Я пытался использовать чек IsMouseOver для каждого ключа управления, как предложено @Sentient, но как ни странно, что только дает истинное, когда событие MouseUp обрабатывается.

+1

бы с помощью .IsMouseOver из ваших управления работают? Я не знаю, правильно ли это регистрируется, когда есть несколько касаний одновременно. – Sentient

+0

Увы, это не работает на Android. Он запускается во время события MouseUp, а не во время MouseDown. – Arnold

ответ

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; 
+1

«Я автор ...» всегда является хорошим началом для ответа SO. +1. Интересные связанные серии сообщений в блогах тоже. –

+0

Большое спасибо за эту разработку. Кажется, вы решили проблему перевода в и из экранных координат. Насколько я понял ваш блог, вы также используете этот код для музыкальной клавиатуры. У вас создается впечатление, что реакция этого кода на самом деле медленнее обработчика событий OnMouseDown? – Arnold

+0

Да, он использовался для музыкальной клавиатуры. Я делал порт приложения под названием Piano Wizard для iOS. Что касается скорости, я думаю, что это не должно быть медленнее, чем OnMouseDown. – Runner

Смежные вопросы