Нажмите \ пролистайте пустую область 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
}