Используйте два MouseAreas одновременно в Android

Мне нужно эмулировать нажатие клавиши управления на планшетном ПК, на котором нет физической клавиатуры. Для этого у меня есть экранная плавающая кнопка, которую пользователь может использовать для достижения этой цели.

Проблема, однако, в том, что может быть только один MouseArea который получает сенсорные события. Если один имеет фокус, остальные игнорируются. Что, очевидно, проблематично, так как это делает невозможным нажатие и удерживание кнопки управления и нажатие на какой-либо другой элемент GUI.

Обратите внимание, что мне не нужно мультитач в буквальном контексте - мне нужно только одно касание на область мыши, мне просто нужно несколько областей мыши для одновременной работы. Это плюс причина того, что MultiPointTouchAreaAPI специально адаптирован для реального мультитач и не имеет необходимых мне свойств, функциональных возможностей (наведение курсора) и удобство, поэтому я не очень хочу его использовать, даже если он предположительно обратно совместим с мышью вход.

Я подозреваю, что это ограничение связано с тем, что прикосновение было включено в MouseArea вместо того, чтобы быть гражданином первого класса, и базовая реализация - это своего рода сделка " один курсор на правило их всех", но все же, может быть, есть какой-нибудь способ заставить работать одновременно несколько областей мыши?

Хорошо, вот тривиальный пример - нажатие левой или правой стороны экрана превращает его соответственно в синий и красный, однако невозможно нажать одну, если другая уже нажата.

Window {
  id: main
  visible: true
  width: 600
  height: 300

  Row {
    Rectangle {
      width: main.width * .5
      height: main.height
      color: m1.pressed ? "blue" : "black"
      MouseArea {
        id: m1
        anchors.fill: parent
      }
    }
    Rectangle {
      width: main.width * .5
      height: main.height
      color: m2.pressed ? "red" : "black"
      MouseArea {
        id: m2
        anchors.fill: parent
      }
    }
  }
}

1 ответ

Ну, через 2 года и без ответов... Я расскажу всю свою историю, чтобы никто не пытался делать то же, что мы делали, и терять время. Идите ниже линии (немного под изображением), чтобы пропустить это.

У нас была та же проблема, даже больше, потому что мы разработали всю нашу систему с помощью фразы, которую вы сказали:

даже если предположительно обратно совместим с мышью

в виду, время после того, как мы увидели, что у нас были проблемы.

Подумав, как мы могли бы решить эту проблему, мы сначала попробовали рекурсивную функцию для поиска по всем областям мыши и для каждой точки касания сгенерировали поддельное событие мыши с активным флагом Qt.MouseEventSynthesizedByApplication, и область мыши может быть использована для обработки этого события, и вызвать соответствующие обратные вызовы.

Здесь я поместил изображение неисправного кода, чтобы люди, которые спешат, не копировали его... Он не закончен, и у нас все еще были проблемы с выяснением того, как обрабатывать несколько касаний. Неудачный код

Кажется, что когда у вас есть более одного касания в мышиной области, поведение, закодированное для этого сценария, не имеет смысла, потому что в системе должна быть только одна мышь.

Затем мы провели поиск в сети и обнаружили удаленный пост 2009 года в веб-архиве форума qt человека с похожей проблемой, и опубликовали странный код (который не работает на qt5), чтобы обмануть мышиную область для принятия этих событий. Это дало нам идею сгенерировать себе событие, которое должно произойти, и вызвать сигнал из соответствующей мышиной области с помощью события поддельной мыши.

Это сработало, за исключением сигнала нажатой мыши (MouseEvent), который не может быть активирован. Это дало ошибки.

После этого мы попытались обнародовать сигналы (путем явного объявления на мышиной территории)

property var toques = []
visible: false
property var pressed
onPressed: pressed = true
onReleased: pressed = false

Это сделало нас на шаг ближе, но это потребует реализации каждого события мыши, и, кроме того, существует перемежаемость между всеми касаниями (поскольку мы можем инициировать каждый сигнал для каждого касания), и поведение может быть неопределенным. Кроме того, тот факт, что в касаниях не было порядка отслеживания того, что произошло, заставил нас отказаться от мышиной области для этого случая.


Тогда мы использовали MutiPointTouchArea для обработки событий. Мы увидели, что использование нескольких MultiPointTouchArea(s) не дает ошибок и может обрабатывать несколько нажатий (от прикосновений) для приложения.

Все, что вам нужно сделать, это заменить MouseAreas на Multitouch и реализовать для себя все желаемое поведение, такие понятия, как hover, не имеют смысла в этом контексте, так как мы обрабатываем прикосновения. Вы можете использовать давление, чтобы сделать что-то подобное. Мы помещаем компонент Rectangle, чтобы сохранить интересующие нас переменные / сигналы и быть замененными из MultiTouchArea при выполнении определенных действий. Здесь я реализую ваш тривиальный пример на основе этой идеи:

Window {
  id: main
  visible: true
  width: 600
  height: 300

  Row {
    Rectangle {
      width: main.width * .5
      height: main.height
      property var lol: false
      color: ispressed ? "blue" : "black"
      MultiPointTouchArea {
        id: m1
        anchors.fill: parent
        onPressed: parent.ispressed= true
        onReleased: parent.ispressed= false
      }
    }
    Rectangle {
      width: main.width * .5
      height: main.height
      x:main.width * .5
      property var ispressed: false
      color: ispressed ? "red" : "black"
      MultiPointTouchArea {
        id: m2
        anchors.fill: parent
        onPressed: parent.ispressed= true
        onReleased: parent.ispressed= false
      }
    }
  }
}

Как вы видите, Rectangle (ваша кнопка или что-то еще) имеет свойства, которые имеют значение, в данном случае он нажимается и изменяется дочерним объектом (MultipointToucArea) в соответствии с нашим определенным поведением, в этом случае активируется, когда его нажимают, и отпустите, когда он отпустит, обратите внимание, что в этом случае цвет погаснет, только потянув один палец, потому что срабатывает onReleased.

Возможно, вам придется решить, какое поведение будет правильным для вашего приложения в каждом конкретном случае. Сигналов, подаваемых для программирования этого, было более чем достаточно в нашем случае:

canceled(list<TouchPoint> touchPoints)
gestureStarted(GestureEvent gesture)
pressed(list<TouchPoint> touchPoints)
released(list<TouchPoint> touchPoints)
touchUpdated(list<TouchPoint> touchPoints)
updated(list<TouchPoint> touchPoints)

Также вы можете видеть, что нажатие происходит только в первой области, к которой вы прикоснулись, поэтому, если вы продолжите удерживать палец в других областях мыши, на них не будет вызвано нажатие, поэтому, играя с updated(), вы сможете получить следует ли это активировать вещи или нет.

Это решение, которое мы получили, и работали для нас, мы не могли придумать ничего лучше, и для кликов / нажатий на события это помогает.

Надеюсь, поможет.

Другие вопросы по тегам