首页 文章

新的拖放机制在Qt-Quick(Qt 5.3)中无法正常工作

提问于
浏览
9

我尝试使用新的QML类型 DragDragEventDropArea 在Qt 5.3中实现拖放 . 这是来自documentation of the QML Drag type的原始示例,并进行了一些小的修改:

import QtQuick 2.2

Item {
    width: 800; height: 600

    DropArea {
        width: 100; height: 100; anchors.centerIn: parent

        Rectangle {
            anchors.fill: parent
            color: parent.containsDrag ? "red" : "green"
        }

        onEntered: print("entered");
        onExited: print("exited");
        onDropped: print("dropped");
    }

    Rectangle {
        x: 15; y: 15; width: 30; height: 30; color: "blue"

        Drag.active: dragArea.drag.active
        // Drag.dragType: Drag.Automatic
        Drag.onDragStarted: print("drag started");
        Drag.onDragFinished: print("drag finished");

        MouseArea {
            id: dragArea
            anchors.fill: parent
            drag.target: parent
        }
    }
}

Expected behaviour :可以使用鼠标拖动小的蓝色矩形(拖动目标) . 如果拖过窗口中央较大的绿色矩形,此矩形会在离开时变为红色并返回绿色 . 此外,dragStarted,enter,exited,drop和dragFinished信号及时发出,相应的信号处理程序打印出它们的消息 .

Experienced behaviour

取决于 Drag.dragType (见上面的注释行):

  • Drag.dragType 未设置(默认为 Drag.Internal ):

拖放按照描述工作,但只发出输入和退出的信号 . 其他信号(dragStarted,dragFinished和drop)被抑制 . 所以没有办法对 DropArea 中的下降做出反应 .

  • Drag.dragType 设置为 Drag.Automatic

现在所有信号都会发出,但蓝色矩形(拖动目标)不随鼠标移动 . 相反,鼠标光标会更改其形状以显示可能的放置目标 . 释放鼠标后,蓝色矩形跳转到最新的鼠标位置 .

这两种变体都不令人满意 . 如何获取所有信号并仍能拖动拖动目标?不幸的是,文档是关于QML拖放的一切,但特别是关于不祥的 Drag.dragType .

2 回答

  • 18

    如果打开the QQuickDrag source code并查看由 Drag.Internal 使用的 start()Drag.Automatic 使用的 startDrag() 之间的差异,则差异非常明显 . start() sets up an event change listener,然后它用于附加对象的update the position . startDrag() doesn't do this .

    为什么这样工作?我不知道! QtQuick 2拖放文档肯定有改进的余地 .

    有一个相当简单的解决方法:从两个世界中获取最佳效果 . 使用 Drag.Automatic ,但不是设置 Drag.active ,而是手动调用 start()drop() . 它不会调用 Drag.onDragStarted()Drag.onDragFinished() ,但你实际上通过在 MouseAreadrag.active 中监听更改来获得免费的 .

    这是运作中的概念:

    import QtQuick 2.0
    
    Item {
        width: 800; height: 600
    
        DropArea {
            width: 100; height: 100; anchors.centerIn: parent
    
            Rectangle {
                anchors.fill: parent
                color: parent.containsDrag ? "red" : "green"
            }
    
            onEntered: print("entered");
            onExited: print("exited");
            onDropped: print("dropped");
        }
    
        Rectangle {
            x: 15; y: 15; width: 30; height: 30; color: "blue"
    
            // I've added this property for simplicity's sake.
            property bool dragActive: dragArea.drag.active
    
            // This can be used to get event info for drag starts and 
            // stops instead of onDragStarted/onDragFinished, since
            // those will neer be called if we don't use Drag.active
            onDragActiveChanged: {
                if (dragActive) {
                    print("drag started")
                    Drag.start();
                } else {
                    print("drag finished")
                    Drag.drop();
                }
            }
    
            Drag.dragType: Drag.Automatic
    
            // These are now handled above.
            //Drag.onDragStarted: print("drag started");
            //Drag.onDragFinished: print("drag finished");
    
            MouseArea {
                id: dragArea
                anchors.fill: parent
                drag.target: parent
            }
        }
    }
    

    我意识到这不是一个完全令人满意的解决方案,但它确实符合您的预期行为 .

    该解决方案提供:

    • 所有所需事件的通知:拖动开始,拖动完成,输入拖动区域,退出拖动区域,然后拖放到拖动区域 .

    • 拖动动画由QtQuick自动处理 . 正方形不会像使用 Drag.Automatic 运行示例代码时那样冻结 .

    它没有提供什么:

    • 解释为什么QtQuick 's drag and drop functionality works this way, or whether it'甚至是开发人员的预期行为 . 目前的文件似乎含糊不清 .
  • 3

    我自己遇到了这个问题(使用Qt 5.2,但同样存在问题) . 我在X轴上的've got a '滑块框,只想知道拖动完成的时间...而不是响应沿途的每个位置变化 . 我的解决方法涉及破解状态/转换,用 ScriptAction 来提供逻辑 . 这是用于模仿对"onDragFinished"信号的响应的简化版本 . 因此,虽然它不会覆盖所有拖放信号,但它可能会让您指向正确的方向 .

    Rectangle {
        id: sliderControl
    
        height: coordinates.height
        width: 80
        color: "#F78181"
        border.color: "#FE2E2E"
        border.width: 1
        opacity: 0.4
    
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            drag.target: sliderControl
            drag.axis: Drag.XAxis
            drag.minimumX: 0
            drag.maximumX: view.width - sliderControl.width
            hoverEnabled: true
        }
    
        states: [
            State {
                name: "dragging"
                when: mouseArea.drag.active
            },
            State {
                name: "finished_dragging"
                when: !mouseArea.drag.active
            }
        ]
    
        transitions: [
            Transition {
                from: "dragging"
                to: "finished_dragging"
                ScriptAction {
                    script: console.log("finished dragging script");
                }
            }
        ]
    }
    

    ps - 我知道这样的'workaround'也不知道's going on with QML' s Drag.dragType 是什么 .

相关问题