Нажмите \ пролистайте пустую область Flickable, которая частично перекрывает другую Flickable

У меня есть "редактор" сцены, который можно перевернуть снизу, и закрепленный справа от него, поверх него можно перевернуть "контур", который показывает дерево структуры сцены.

  Flickable {
    id: editor
    anchors.fill: parent
    contentWidth: 5000
    contentHeight: 5000
    Repeater {
      model: 500
      delegate: Rectangle {
        width: Math.random() * 200 + 50
        height: width
        x: Math.random() * editor.contentWidth
        y: Math.random() * editor.contentHeight
        color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
        border.color: "black"
      }
    }
  }

  Flickable {
    id: outliner
    anchors.right: editor.right
    width: contentWidth
    height: parent.height
    contentWidth: contentItem.childrenRect.width
    contentHeight: contentItem.childrenRect.height
    Column {
      Repeater {
        model: 500
        delegate: Rectangle {
          width: Math.random() * 200 + 50
          x: outliner.contentWidth - width
          height: 50
          color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
          border.color: "black"
        }
      }
    }
  }

Естественно, я хочу иметь возможность переключать оба, чтобы перемещаться по обоим, так как они оба становятся больше, чем доступное пространство экрана.

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

Я не смог сделать это из-за того, как Flickable работает. Сначала он будет проверять наличие перетаскивания, и только если щелчок не превышает порог перетаскивания, он пропустит щелчок до нижележащих элементов. Поэтому я не могу придумать способ щелкнуть мышью, только если в этой позиции находится объект.

Можно ли как-то заставить обработчик событий делать то, что я хочу?

2 ответа

Решение

Mkay, я думаю, что я сделал это, ключ должен был отключить интерактивность для outliner, а затем перехватить ввод через MouseArea в делегате, затем тщательно определите время и измерьте дельта ручного перетаскивания и, если достаточно быстро, запланируйте ручное переключение при выпуске.

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

Я также добавил поддержку колес и тому подобное.

Если кто-то испытывает проблемы с ним на любой платформе, сообщите мне об этом в комментариях.

// the editor code is the same from the OP
  Flickable {
    id: outliner
    anchors.right: editor.right
    width: contentWidth
    height: parent.height
    contentWidth: contentItem.childrenRect.width
    contentHeight: contentItem.childrenRect.height
    interactive: false
    property int ly: 0
    property real lt: 0
    property int dy: 0
    function go(yy) {
      dy = contentY - (contentY -= yy - ly)
      ly = yy
      lt = Date.now()
    }
    Timer { 
      id: trigger
      interval: 1
      onTriggered: outliner.flick(0, outliner.dy * 150)
    }
    Column {
      Repeater {
        model: 500
        delegate: Rectangle {
          width: Math.random() * 200 + 50
          x: outliner.contentWidth - width
          height: 50
          color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
          border.color: "black"
          MouseArea {
            anchors.fill: parent
            Drag.active: drag.active
            drag.target: Item { id: dummy }
            onPressed: {
              dummy.y = 0
              if (outliner.flicking) outliner.cancelFlick()
            }
            onWheel: outliner.flick(0, wheel.angleDelta.y * 10)
            onPositionChanged: {
              if (drag.active) outliner.go(dummy.y)
            }
            onReleased: {
              if (Date.now() - outliner.lt < 50) trigger.start()
              outliner.ly = 0
              outliner.returnToBounds()
            }
          }
        }
      }
    }
  }

Вы можете сделать это, проверяя каждое нажатие на сцену, если ниже пресса есть делегат планировщика. Если нет, отметьте outliner как не интерактивный. Включите его сразу после того, как в editor,

Вот так:

import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 2.0

ApplicationWindow {
    id: app
    visible: true
    width: 600
    height: 480
    Item { // a common parent not containing the MouseArea to be able to call childAt on press
        id: flickablesParent
        anchors.fill: parent
        Flickable {
            id: editor
            anchors.fill: parent
            contentWidth: 5000
            contentHeight: 5000
            onMovementStarted: outliner.interactive = true //re-enable the outliner user interaction so it can be flicked again.
            Repeater {
                model: 500
                delegate: Rectangle {
                    width: Math.random() * 200 + 50
                    height: width
                    x: Math.random() * editor.contentWidth
                    y: Math.random() * editor.contentHeight
                    color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
                    border.color: "black"
                }
            }
        }

        Flickable {
            id: outliner
            anchors.right: editor.right
            width: contentWidth
            height: parent.height
            contentWidth: contentItem.childrenRect.width
            contentHeight: contentItem.childrenRect.height

            Column {
                id: column // set an id so it can be referenced in the MouseArea
                Repeater {
                    model: 500
                    delegate: Rectangle {
                        width: Math.random() * 200 + 50
                        x: outliner.contentWidth - width
                        height: 50
                        color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
                        border.color: "black"
                    }
                }
            }
        }
    }
    MouseArea {
        id: dispatcher
        anchors.fill: parent
        onPressed: {
            var flickable = flickablesParent.childAt(mouse.x, mouse.y); //find out on what flickable we pressed (the check could be ommited but I guess it's more performant with)
            if (flickable === outliner) {
                var mappedPos = mapToItem(column, mouse.x, mouse.y);
                var delegate = column.childAt(mappedPos.x, mappedPos.y);
                if (!delegate)
                    outliner.interactive = false; //if there's no delegate where we pressed in the column, we disable the interactions of the outliner flickable.
            }
            mouse.accepted = false; // let the underlying Flickable deal with this event
        }
    }
}

РЕДАКТИРОВАТЬ: вам не нужно повторно включить планировщик в onMovementStarted, вы можете сделать это в MouseArea onPressed тоже.

лайк

onPressed: {
    var flickable = flickablesParent.childAt(mouse.x, mouse.y); //find out on what flickable we pressed (the check could be ommited but I guess it's more performant with)
    if (flickable === outliner) {
        var mappedPos = mapToItem(column, mouse.x, mouse.y);
        var delegate = column.childAt(mappedPos.x, mappedPos.y);
        outliner.interactive = delegate ? true : false;
    }
    mouse.accepted = false; // let the underlying Flickable deal with this event
}
Другие вопросы по тегам