【问题标题】:New drag-and-drop mechanism does not work as expected in Qt-Quick (Qt 5.3)新的拖放机制在 Qt-Quick (Qt 5.3) 中无法按预期工作
【发布时间】:2014-08-23 07:33:45
【问题描述】:

我尝试使用新的 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
        }
    }
}

预期行为:可以用鼠标拖动蓝色小矩形(拖动目标)。如果拖动到窗口中心较大的绿色矩形上,该矩形会在离开时变为红色并变回绿色。此外,信号dragStartedenteredexiteddroppeddragFinished是及时发出,相应的信号处理程序打印出它们的消息。

经验丰富的行为

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

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

    拖放操作如前所述,但仅发出 enteredexited 信号。其他信号(dragStarteddragFinisheddropped)被抑制。所以没有办法对DropArea的下降做出反应。

  2. Drag.dragType 设置为Drag.Automatic

    现在所有信号都发出了,但是蓝色矩形(拖动目标)没有随着鼠标移动。相反,鼠标光标会改变其形状以可视化可能的放置目标。释放鼠标后,蓝色矩形会跳转到最新的鼠标位置。

这两种变体都不令人愉悦。我怎样才能获得所有信号并且仍然能够在拖动目标周围拖动?不幸的是,文档对 QML 中的拖放操作一无所知,尤其是关于不祥的 Drag.dragType

【问题讨论】:

    标签: qt drag-and-drop qml qt5 qt-quick


    【解决方案1】:

    如果您打开the QQuickDrag source code 并查看Drag.Internal 使用的start()Drag.Automatic 使用的startDrag() 之间的区别,区别非常明显。 start() sets up an event change listener,然后将其用于附加对象的update the positionstartDrag() 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 的拖放功能会以这种方式工作,或者这是否是开发人员的预期行为。当前的文档似乎模棱两可。

    【讨论】:

    • 感谢您的详细解答。尽管我仍然对不同的拖动类型感到困惑,但您的解决方案满足了我的需求,因为它模拟了所需的事件,因此可以解耦拖动源和放置区域。尽管如此,我认为 Qt 团队应该增强 QtQuick DnD,因为它并不是真正有用和直观。
    • 请注意,Qt 5.15.x 中的情况并没有改变,仍然需要这篇文章中的解决方法。
    【解决方案2】:

    我自己也遇到过这个问题(使用 Qt 5.2,但那里也存在同样的问题)。我在 X 轴上有一个“滑块”,只是想知道拖动何时完成……而不是响应沿途的每个位置变化。我的解决方法涉及破解状态/转换,使用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 - 我知道这样的“解决方法”不符合赏金参数的条件,但是当我搜索有关该问题的帮助时,我很沮丧地只找到您的问题(没有解决方案)。希望其他在这条路上跌跌撞撞的人会发现这很有用。不幸的是,我也不知道 QML 的 Drag.dragType 发生了什么。

    【讨论】:

    • 感谢您的回答。我很高兴我并不孤单! ;) 我也已经尝试过一些类似的解决方案,但不幸的是,在我的“真实”代码中,拖动启动MouseArea 完全独立于应该处理下降的DropArea。因此,将 drop 事件从 MouseArea 传递到 DropArea 是相当复杂的/如果没有 hack 几乎是不可能的。我开始认为 QtQuick 中的 DnD 机制在某种程度上被破坏了......
    猜你喜欢
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多