MFC如何实现鼠标拖拽?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC如何实现鼠标拖拽?相关的知识,希望对你有一定的参考价值。

比如我按住左键不放,可以画图画线,直到松开后停止。
不要只说个用OnLButtonDown,我要详细点的过程,
或者是是按住左键,图片可以虽鼠标一起移动

参考技术A bool g_bDrawFlag = false;
CPoint oldPoint;
void CTestDlg::OnLButtonDown(UINT nFlags, CPoint point)

CDialog::OnLButtonDown(nFlags, point);
g_bDrawFlag = true;
oldPoint = point;


void CTestDlg::OnMouseMove(UINT nFlags, CPoint point)

CDialog::OnMouseMove(nFlags, point);

if(g_bDrawFlag)

CClientDC dc(this);
MoveToEx(dc,oldPoint.x, oldPoint.y, NULL);
LineTo(dc, point.x, point.y);
oldPoint = point;


void CTestDlg::OnLButtonUp(UINT nFlags, CPoint point)

CDialog::OnLButtonUp(nFlags, point);
g_bDrawFlag = false;
本回答被提问者和网友采纳

JavaScript 拖拽实现

一、普通实现

拖拽实现原理:

  1. 鼠标点击 后 ,记录当前鼠标位置
  2. 鼠标移动
    1. 拖拽元素 左侧 定位位置 = 拖拽元素 与 定位参考父级 左侧的距离 + 移动鼠标位置 X 轴值 减去 之前记录的鼠标位置 X 轴值
    2. 拖拽元素 顶部 定位位置 = 拖拽元素 与 定位参考父级 顶部的距离 + 移动鼠标位置 Y 轴值 减去 之前记录的鼠标位置 Y 轴值

鼠标 与 拖拽元素 位置变化关系

  1. 第二次点击 left 位置 = 第一次当时的 offsetLeft + (第二次 client.X - 第一次 client.X)
  2. 每次 拖拽元素 移动之后, oldX 会变化,需要重新赋值
  3. 运动条件: 按下后再移动
    1. onmousedown
      1. onmousemove(在 onmousedown 中注册 onmousemove 事件)
    2. onmouseup

备注:

实现拖拽功能,一开始的想法是,鼠标移动到哪里,拖拽元素就移动到哪里

那么是否可以直接设置元素的 left 和 top 为 鼠标的 clientX 和 clientY 呢

然而这种做法仅限于鼠标点击元素左上角进行移动;

若点击在元素中间部位,那么此刻的 clientX 和 clientY 设置成 left 和 top 后

元素将会闪退部分长度,而后跟随鼠标移动


全局拖拽

全局拖拽测试用例

css

#dragson {
    position: absolute;
    width: 100px;
    height: 100px;
    background-color: blue;
}

html

<div id="dragson"></div>

js

let dragSon = document.getElementById(‘dragson‘)
// 鼠标按下
dragSon.onmousedown = function(e) {
    // 兼容 IE
    let ev = e || window.event,
        // 存储当前鼠标位置
        oldX = ev.clientX,
        oldY = ev.clientY

    // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
    if (window.event) {
        // 兼容 IE
        window.event.returnValue = false;
    } else {
        ev.preventDefault()
    }

    // 因为鼠标移动过快,可能会移出拖拽元素的范围
    // 这里使用 document.documentElement.onmousemove 来解决
    document.documentElement.onmousemove = function(e) {
        let ev = e || window.event,
            newX = ev.clientX,
            newY = ev.clientY,
            // 拖拽元素 距离 `定位参考父级` 左侧的距离 + `移动鼠标位置 X 轴值` 减去 `之前记录的鼠标位置 X 轴值`
            // offsetLeft: 拖拽元素与父级左侧的距离长度(不含父级边框)
            endX = dragSon.offsetLeft + newX - oldX,
            // 拖拽元素 距离 `定位参考父级` 顶部的距离 + `移动鼠标位置 Y 轴值` 减去 `之前记录的鼠标位置 Y 轴值`
            // offsetTop: 拖拽元素与父级顶部的距离长度(不含父级边框)
            endY = dragSon.offsetTop + newY - oldY
        
        // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
        if (window.event) {
            // 兼容 IE
            window.event.returnValue = false;
        } else {
            ev.preventDefault()
        }

        // 设置拖拽元素位置
        dragSon.style.left = endX + ‘px‘
        dragSon.style.top = endY + ‘px‘

        // 新旧值交换
        oldX = newX
        oldY = newY
    }
}
// 鼠标松开
document.documentElement.onmouseup = function(e) {
    // 函数赋值为 null,让函数失效,便于浏览器垃圾回收
    document.documentElement.onmousemove = null
}

限制父级内拖拽

限制父级内拖拽测试用例

css

#dragparent {
    position: relative;
    width: 500px;
    height: 500px;
    border: 1px solid red
}
#dragson {
    position: absolute;
    width: 100px;
    height: 100px;
    background-color: blue;
}

html

<div id="dragparent">
    <div id="dragson"></div>
</div>

js

let dragParent = document.getElementById(‘dragparent‘),
    dragSon = document.getElementById(‘dragson‘)
// 鼠标按下
dragSon.onmousedown = function(e) {
    // 兼容 IE
    let ev = e || window.event,
        // 存储当前鼠标位置
        oldX = ev.clientX,
        oldY = ev.clientY

    // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
    if (window.event) {
        // 兼容 IE
        window.event.returnValue = false;
    } else {
        ev.preventDefault()
    }

    // 因为鼠标移动过快,可能会移出拖拽元素的范围
    // 这里使用 document.documentElement.onmousemove 来解决
    document.documentElement.onmousemove = function(e) {
        let ev = e || window.event,
            newX = ev.clientX,
            newY = ev.clientY,
            // 拖拽元素 距离 `定位参考父级` 左侧的距离 + `移动鼠标位置 X 轴值` 减去 `之前记录的鼠标位置 X 轴值`
            // offsetLeft: 拖拽元素与父级左侧的距离长度(不含父级边框)
            endX = dragSon.offsetLeft + newX - oldX,
            // 拖拽元素 距离 `定位参考父级` 顶部的距离 + `移动鼠标位置 Y 轴值` 减去 `之前记录的鼠标位置 Y 轴值`
            // offsetTop: 拖拽元素与父级顶部的距离长度(不含父级边框)
            endY = dragSon.offsetTop + newY - oldY
        
        // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
        if (window.event) {
            // 兼容 IE
            window.event.returnValue = false;
        } else {
            ev.preventDefault()
        }

        // 限制在 定位参考父级元素 内移动
        // 左边界
        if (endX <= 0) {
            endX = 0
        }
        // 右边界
        // X 轴方向可移动距离 = 父级内部宽度 - 拖拽元素宽度
        if (endX >= dragParent.clientWidth - dragSon.clientWidth) {
            endX = dragParent.clientWidth - dragSon.clientWidth
        }
        
        // 上边界
        if (endY <= 0) {
            endY = 0
        }
        // 下边界
        // Y 轴方向可移动距离 = 父级内部高度 - 拖拽元素高度
        if (endY >= dragParent.clientHeight - dragSon.clientHeight) {
            endY = dragParent.clientHeight - dragSon.clientHeight
        }

        // 设置拖拽元素位置
        dragSon.style.left = endX + ‘px‘
        dragSon.style.top = endY + ‘px‘

        // 新旧值交换
        oldX = newX
        oldY = newY
    }
}
// 鼠标松开
document.documentElement.onmouseup = function(e) {
    // 函数赋值为 null,让函数失效,便于浏览器垃圾回收
    document.documentElement.onmousemove = null
}

二、封装

封装测试用例

实现对 拖拽 功能的 类封装

class Drag {
    constructor(option) {
        this.oldX = 0
        this.oldY = 0
        this.newX = 0
        this.newY = 0
        this.maxMoveWidth = 0
        this.maxMoveHeight = 0

        if (!option.dragEle) throw ‘拖拽元素 dragEle 必须传递‘
        this.dragSon = option.dragEle

        if (option.parent) {
            this.dragParent = option.parent
            this.maxMoveWidth = this.dragParent.clientWidth - this.dragSon.clientWidth
            this.maxMoveHeight = this.dragParent.clientHeight - this.dragSon.clientHeight
        }

        this.init()
    }
    // 初始化
    init() {
        // 鼠标按下
        this.dragSon.onmousedown = e => {
            // 兼容 IE
            let ev = e || window.event

            // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
            if (window.event) {
                // 兼容 IE
                window.event.returnValue = false;
            } else {
                ev.preventDefault()
            }

            // 存储当前鼠标位置
            this.oldX = ev.clientX
            this.oldY = ev.clientY

            this.dragMove()
        }

        // 鼠标松开
        document.documentElement.onmouseup = function(e) {
            // 函数赋值为 null,让函数失效,便于浏览器垃圾回收
            document.documentElement.onmousemove = null
        }
    }
    // 鼠标移动
    dragMove() {
        // 因为鼠标移动过快,可能会移出拖拽元素的范围
        // 这里使用 document.documentElement.onmousemove 来解决
        document.documentElement.onmousemove = e => {
            let ev = e || window.event, endX, endY

            // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
            if (window.event) {
                // 兼容 IE
                window.event.returnValue = false;
            } else {
                ev.preventDefault()
            }

            this.newX = ev.clientX,
            this.newY = ev.clientY,
            // 拖拽元素 距离 `定位参考父级` 左侧的距离 + `移动鼠标位置 X 轴值` 减去 `之前记录的鼠标位置 X 轴值`
            // offsetLeft: 拖拽元素与父级左侧的距离长度(不含父级边框)
            endX = this.dragSon.offsetLeft + this.newX - this.oldX,
            // 拖拽元素 距离 `定位参考父级` 顶部的距离 + `移动鼠标位置 Y 轴值` 减去 `之前记录的鼠标位置 Y 轴值`
            // offsetTop: 拖拽元素与父级顶部的距离长度(不含父级边框)
            endY = this.dragSon.offsetTop + this.newY - this.oldY

            // 若存在父级,限制在父级范围内移动
            if (this.dragParent) {
                let { limitEndX, limitEndY } = this.limitRange(endX, endY)
                endX = limitEndX
                endY = limitEndY
            }

            // 设置拖拽元素位置
            this.dragSon.style.left = endX + ‘px‘
            this.dragSon.style.top = endY + ‘px‘

            // 新旧值交换
            this.oldX = this.newX
            this.oldY = this.newY
        }
    }
    // 限制移动范围
    limitRange(endX, endY) {
        // 限制在 定位参考父级元素 内移动
        // 左边界
        if (endX <= 0) {
            endX = 0
        }
        // 右边界
        // X 轴方向可移动距离 = 父级内部宽度 - 拖拽元素宽度
        if (endX >= this.maxMoveWidth) {
            endX = this.maxMoveWidth
        }
        
        // 上边界
        if (endY <= 0) {
            endY = 0
        }
        // 下边界
        // Y 轴方向可移动距离 = 父级内部高度 - 拖拽元素高度
        if (endY >= this.maxMoveHeight) {
            endY = this.maxMoveHeight
        }
        return { limitEndX: endX, limitEndY: endY }
    }
}

三、支持移动端

支持移动端测试用例

class Drag {
    constructor(option) {
        this.oldX = 0
        this.oldY = 0
        this.newX = 0
        this.newY = 0
        this.maxMoveWidth = 0
        this.maxMoveHeight = 0

        this.isMobile = false
        if (‘ontouchstart‘ in window) {
            this.isMobile = true
        }

        this.eventType = {
            start: this.isMobile ? ‘ontouchstart‘ : ‘onmousedown‘,
            move: this.isMobile ? ‘ontouchmove‘ : ‘onmousemove‘,
            end: this.isMobile ? ‘ontouchend‘ : ‘onmouseup‘,
        }

        if (!option.dragEle) throw ‘拖拽元素 dragEle 必须传递‘
        this.dragSon = option.dragEle

        if (option.parent) {
            this.dragParent = option.parent
            this.maxMoveWidth = this.dragParent.clientWidth - this.dragSon.clientWidth
            this.maxMoveHeight = this.dragParent.clientHeight - this.dragSon.clientHeight
        }

        this.init()
    }
    // 初始化
    init() {
        // 鼠标按下
        this.dragSon[this.eventType[‘start‘]] = e => {
            // 兼容 IE
            let ev = e || window.event

            // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
            if (window.event) {
                // 兼容 IE
                window.event.returnValue = false;
            } else {
                ev.preventDefault()
            }

            if (this.isMobile) {
                ev = ev.touches[0]
            }

            // 存储当前鼠标位置
            this.oldX = ev.clientX
            this.oldY = ev.clientY

            this.dragMove()
        }
        
        // 鼠标松开
        document.documentElement[this.eventType[‘end‘]] = e => {
            // 函数赋值为 null,让函数失效,便于浏览器垃圾回收
            document.documentElement[this.eventType[‘move‘]] = null
        }
    }
    // 鼠标移动
    dragMove() {
        // 因为鼠标移动过快,可能会移出拖拽元素的范围
        // 这里使用 document.documentElement.onmousemove 来解决
        document.documentElement[this.eventType[‘move‘]] = e => {
            let ev = e || window.event, endX, endY

            // 阻止默认事件 ,即鼠标悬停在拖拽元素上,系统选中内容
            if (window.event) {
                // 兼容 IE
                window.event.returnValue = false;
            } else {
                ev.preventDefault()
            }
            
            if (this.isMobile) {
                ev = ev.touches[0]
            }

            this.newX = ev.clientX,
            this.newY = ev.clientY,
            // 拖拽元素 距离 `定位参考父级` 左侧的距离 + `移动鼠标位置 X 轴值` 减去 `之前记录的鼠标位置 X 轴值`
            // offsetLeft: 拖拽元素与父级左侧的距离长度(不含父级边框)
            endX = this.dragSon.offsetLeft + this.newX - this.oldX,
            // 拖拽元素 距离 `定位参考父级` 顶部的距离 + `移动鼠标位置 Y 轴值` 减去 `之前记录的鼠标位置 Y 轴值`
            // offsetTop: 拖拽元素与父级顶部的距离长度(不含父级边框)
            endY = this.dragSon.offsetTop + this.newY - this.oldY
            
            // 若存在父级,限制在父级范围内移动
            if (this.dragParent) {
                let { limitEndX, limitEndY } = this.limitRange(endX, endY)
                endX = limitEndX
                endY = limitEndY
            }

            // 设置拖拽元素位置
            this.dragSon.style.left = endX + ‘px‘
            this.dragSon.style.top = endY + ‘px‘

            // 新旧值交换
            this.oldX = this.newX
            this.oldY = this.newY
        }
    }
    
    // 限制移动范围
    limitRange(endX, endY) {
        // 限制在 定位参考父级元素 内移动
        // 左边界
        if (endX <= 0) {
            endX = 0
        }
        // 右边界
        // X 轴方向可移动距离 = 父级内部宽度 - 拖拽元素宽度
        if (endX >= this.maxMoveWidth) {
            endX = this.maxMoveWidth
        }
        
        // 上边界
        if (endY <= 0) {
            endY = 0
        }
        // 下边界
        // Y 轴方向可移动距离 = 父级内部高度 - 拖拽元素高度
        if (endY >= this.maxMoveHeight) {
            endY = this.maxMoveHeight
        }
        return { limitEndX: endX, limitEndY: endY }
    }
}

以上是关于MFC如何实现鼠标拖拽?的主要内容,如果未能解决你的问题,请参考以下文章

你好,请问在UNITY3D中如何实现用鼠标左键拖拽控制一个组合物体的旋转啊?

在vue脚手架中元素绑定鼠标移动事件onmousemove,当鼠标按下拖拽元素,能在指定元素里左右移动,如何实现?

请问c# 中如何实现在PictureBox中通过鼠标拖拽画出矩形框呢?picturebox中的MouseDown和MouseMove如何使用

three.js加载3ds或obj模型,如何实现鼠标拖拽等功能?

MFC 中Static text 如何响应鼠标hover事件?

MFC编程的时候,改变鼠标光标样式