Qt中如何实现拖拽释放控件

这篇文章将要介绍Qml中如何实现拖拽功能。实现拖拽并释放控件需要下面几个步骤:

  1. 为控件添加鼠标响应事件,监听鼠标移动的横纵坐标。
  2. 根据鼠标的位置移动控件位置。
  3. 修改控件的宿主。

处理鼠标事件

为了处理鼠标事件,我们可以在qml文件中添加一个MouseArea对象。这个对象有位置和大小,但是不可见。这里为了演示MouseArea的使用,我们先添加一个click事件监听。

Rectangle{
        width: 100
        height: 100
        color: "green"

        MouseArea{
            anchors.fill:parent
            onClicked: {
                console.debug("onClick MouseArea")
            }
        }
    }

为了实现拖拽功能,我们需要监听更具体的一些事件。包括press事件、move事件、release事件。

MouseArea{
            anchors.fill:parent
            onClicked: {
                console.debug("onClick MouseArea")
            }
            onPressed: {
                console.debug("onPressed  x:",mouseX," y:",mouseY)
            }
            onPositionChanged: {
                console.debug("onPositionChanged x:",mouseX," y:",mouseY)
            }
            onReleased: {
                console.debug("onReleased  x:",mouseX," y:",mouseY)
            }
        }

onPressed监听鼠标按下事件,onPositionChanged监听鼠标位置变化,onRelease监听鼠标的释放事件。

移动控件

我们可以通过改变控件的x和y坐标来移动控件,这里先将mouseX和mouseY直接赋值给控件。

Rectangle{
        id:rect
        width: 100
        height: 100
        color: "green"

        MouseArea{
            anchors.fill:parent
            onClicked: {
                console.debug("onClick MouseArea")
            }
            onPressed: {
                console.debug("onPressed  x:",mouseX," y:",mouseY)
                rect.x = mouseX
                rect.y = mouseY
            }
            onPositionChanged: {
                console.debug("onPositionChanged x:",mouseX," y:",mouseY)
                rect.x = mouseX
                rect.y = mouseY
            }
            onReleased: {
                console.debug("onReleased  x:",mouseX," y:",mouseY)
                rect.x = mouseX
                rect.y = mouseY
            }
        }
    }

运行后进行拖拽实验,我们发现矩形框不断跳动,与我们期待的结构相差甚远。这里的MouseArea在矩形内部,在拖拽过程中不断修改矩形框的位置,矩形框的位置变换又影响mouseX和mouseY的值,所以矩形框跳动得厉害。如何解决这个问题呢?

  1. 不能直接使用mouseX和mouseY的值,因为这两个值依赖矩形位置。
  2. 通过x和y两个方向上的偏移量控制矩形移动。

使用Item的mapToGlobal 方法将mouseX和mouseY转换成globalX和globalY,避免修改矩形位置后影响MouseArea位置移动计算。通过记录前后两次的位置偏移量移动矩形。

Rectangle{
        id:rect
        width: 100
        height: 100
        x:300
        y:300
        color: "green"

        MouseArea{
            anchors.fill:parent
            property real lastX: 0
            property real lastY: 0
            onClicked: {
                console.debug("onClick MouseArea")
            }
            onPressed: {
                var coordinate = mapToGlobal(mouseX,mouseY)
                lastX = coordinate.x
                lastY = coordinate.y
            }
            onPositionChanged: {
                var coordinate = mapToGlobal(mouseX,mouseY)
                var offsetX = coordinate.x - lastX
                var offsetY = coordinate.y - lastY
                lastX = coordinate.x
                lastY = coordinate.y
                rect.x += offsetX
                rect.y += offsetY
            }
            onReleased: {
                var coordinate = mapToGlobal(mouseX,mouseY)
                var offsetX = coordinate.x - lastX
                var offsetY = coordinate.y - lastY
                lastX = coordinate.x
                lastY = coordinate.y
                rect.x += offsetX
                rect.y += offsetY
            }
        }
    }

经过上面的修改后,矩形拖拽的过程变得特别的顺畅了。

修改宿主

修改宿主指的是修改矩形框的parent,进而改变对象树结构和渲染树结构。

首先我们在拖拽释放的时候需要判断是否要修改矩形框的宿主,使用哪个宿主。这个处理过程需要根据鼠标释放时的坐标位置来判断。

function dockToHost(dragItem, globalX, globalY){
        var local = host1.mapFromGlobal(globalX,globalY)
        if(host1.contains(local)){
            dragItem.x = 0
            dragItem.y = 0
            dragItem.z = 100
            dragItem.parent = host1
            return
        }
        local = host2.mapFromGlobal(globalX, globalY)
        if(host2.contains(local)){
            dragItem.x = 0
            dragItem.y = 0
            dragItem.z = 100
            dragItem.parent = host2
            return
        }
    }

    Rectangle{
        id:host1
        width: 120
        height: 120
        x:100
        y:100
        color: "red"
    }
    Rectangle{
        id:host2
        width: 150
        height: 150
        x:220
        y:220
        color: "blue"
    }

鼠标释放的时候调用dockToHost方法用于确定矩形框改变到哪个宿主上。这里还调用了Item的mapFromGlobal方法将全局坐标转换成item本地坐标,然后判断是否在item区域内。找到宿主item后将矩形框的parent修改成宿主item并将矩形框的坐标重置。

总结

经过上面的步骤后我们可以实现一个简单的控件拖拽功能,并且通过拖拽控件可以改判控件的宿主item。这里主要应用到了MouseArea控件监听鼠标事件,通过改变矩形框的x和y偏移量修改位置。同时为了矩形框移动不影响到MouseArea的mouseX和mouseY,我们使用了mapToGlobal和mapFromGlobal方法来实现全局坐标与局部坐标的相互转换。然后我们通过修改矩形框的parent来改变矩形框的宿主,为宿主item动态添加控件。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 在Qt实现功能有多种方法。以下是其一种常见的实现方式: 1. 首先,在Qt的窗口类重写mousePressEvent、mouseMoveEvent和mouseReleaseEvent三个鼠标事件函数。 2. 在mousePressEvent函数,判断是否按下了鼠标左键,若是,则记录下鼠标的当前位置,同时将需要进行件设置为鼠标捕获状态。例如: ```cpp void MyWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_dragStartPosition = event->pos(); m_isDragging = true; setMouseTracking(true); grabMouse(); event->accept(); } } ``` 3. 在mouseMoveEvent函数,判断是否处于状态,若是,则计算鼠标的位移距离,并更新需要件的位置。例如: ```cpp void MyWidget::mouseMoveEvent(QMouseEvent *event) { if (m_isDragging) { QPoint delta = event->globalPos() - m_dragStartPosition; move(m_dragStartPosition + delta); event->accept(); } } ``` 4. 在mouseReleaseEvent函数,判断是否松开了鼠标左键,若是,则将状态设置为false,并释放鼠标捕获状态。例如: ```cpp void MyWidget::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_isDragging = false; setMouseTracking(false); releaseMouse(); event->accept(); } } ``` 通过以上步骤,就可以实现Qt功能。当鼠标按下左键并件时,件会跟随鼠标的移动而移动。 ### 回答2: 在Qt实现功能通常可以通过以下步骤进行: 1. 首先,需要为件设置属性 `setDragEnabled(true)`,以使其具有可的能力。 2. 在鼠标按下事件 `mousePressEvent` ,通过调用 `QDrag` 类的静态成员函数 `setMimeData` 来设置所需的数据。 3. 接下来,需要在 `mouseMoveEvent` 进行一些处理,使得件能够跟随鼠标的移动进行。可以使用 `QDrag` 类的静态成员函数 `exec` 来启动操作。 4. 在目标件的事件处理函数 `dragEnterEvent` ,需要通过 `event->mimeData()->hasFormat` 来判断数据是否符合预期,并将事件接受标志设置为 `true`。 5. 在目标件的 `dropEvent` ,可以使用 `event->mimeData()` 获取数据,并进行相应的处理。 综上所述,通过设置件的可属性,并在事件处理函数进行数据的设置和行为的处理,可以在Qt实现功能。 ### 回答3: 在Qt,可以通过以下步骤实现功能: 1. 创建一个自定义的件类,并继承QWidget或QGraphicsItem类,这个类将成为可以件。 2. 在件类的构造函数,使用setMouseTracking(true)启用鼠标追踪,以便在鼠标时能够实时检测鼠标位置。 3. 重写件类的mousePressEvent、mouseMoveEvent和mouseReleaseEvent等事件处理函数,以实现效果。 4. 在mousePressEvent函数,检测鼠标按下事件,并记录鼠标按下时的位置。 5. 在mouseMoveEvent函数,检测鼠标移动事件,并计算鼠标的偏移量,然后使用move函数将件按照偏移量进行移动。 6. 在mouseReleaseEvent函数,检测鼠标释放事件,并完成相应的操作,例如保存件的新位置等。 7. 在主窗口或场景,将自定义的件添加到需要的位置,并通过布局或手动设置位置进行定位。 通过以上步骤,就可以实现Qt功能。在实际使用时,可以根据需要对过程进行优化,例如在过程显示边框或阴影效果,限制的范围等。同时,还可以通过重写eventFilter函数实现对其他件的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mjlong123123

你的鼓励时我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值