You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改代码实现多个QPushButton的拖拽功能?

问题描述

需要让多个QPushButton都具备拖拽功能,但目前只有一个按钮能实现拖拽效果。尝试为每个按钮单独编写事件处理函数,代码如下:

class DigitalBoard(QMainWindow):

    def __init__(self):
        super(DigitalBoard, self).__init__()
        
        loadUi("DigitalBoardMain.ui",self)

        self.setAcceptDrops(True)

#For button 1:
    def mouseMoveEvent(self, event):
            event.buttons() == Qt.LeftButton
            mimeData = QMimeData()
            drag = QDrag(self)
            drag.setMimeData(mimeData)
            drag.exec_(Qt.MoveAction)
        
    def dragEnterEvent(self, event):
        event.accept()
    def dropEvent(self, event):
        position = event.pos()
        self.A_1btn.move(position)
        event.accept()

#For button2 
    def mouseMoveEvent1(self, event):
            event.buttons() == Qt.LeftButton
            mimeData = QMimeData()
            drag = QDrag(self)
            drag.setMimeData(mimeData)
            drag.exec_(Qt.MoveAction)
        
    def dragEnterEvent1(self, event1):
        event1.accept()
    def dropEvent1(self, event):
        position1 = event.pos()
        self.A2.move(position1)
        event1.accept()
解决方案

你的写法存在核心问题:Qt的事件系统只会调用类中固定名称的事件处理函数(比如mouseMoveEvent、dragEnterEvent),你自定义的mouseMoveEvent1这类带后缀的函数不会被自动触发。下面提供两种可行的实现方式:

方式一:自定义可拖拽按钮类

创建一个继承自QPushButton的子类,把拖拽逻辑封装进去,所有需要拖拽的按钮都用这个类实例化:

from PyQt5.QtWidgets import QPushButton, QMainWindow
from PyQt5.QtGui import QDrag, QMimeData
from PyQt5.QtCore import Qt

class DraggableButton(QPushButton):
    def mousePressEvent(self, event):
        # 记录鼠标按下时相对于按钮的位置,避免拖拽瞬移
        self.drag_offset = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() != Qt.LeftButton:
            return
        # 创建拖拽对象,以当前按钮作为拖拽源
        mime_data = QMimeData()
        drag = QDrag(self)
        drag.setMimeData(mime_data)
        # 执行拖拽操作
        drag.exec_(Qt.MoveAction)

class DigitalBoard(QMainWindow):
    def __init__(self):
        super().__init__()
        loadUi("DigitalBoardMain.ui", self)
        self.setAcceptDrops(True)

        # 如果你是通过UI文件加载的按钮,需要替换为自定义类实例
        # 示例:
        # self.A_1btn = DraggableButton("按钮1", self)
        # self.A_1btn.setGeometry(100, 100, 100, 50)
        # self.A2 = DraggableButton("按钮2", self)
        # self.A2.setGeometry(200, 100, 100, 50)

    def dragEnterEvent(self, event):
        # 只接受来自自定义按钮的拖拽
        if isinstance(event.source(), DraggableButton):
            event.acceptProposedAction()

    def dropEvent(self, event):
        # 计算按钮最终位置:鼠标位置减去按下时的偏移
        target_pos = event.pos() - event.source().drag_offset
        event.source().move(target_pos)
        event.acceptProposedAction()

方式二:使用事件过滤器(适配UI文件加载的按钮)

如果按钮是通过UI文件加载的,不想修改UI结构,可以给每个按钮安装事件过滤器,统一处理拖拽逻辑:

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtGui import QDrag, QMimeData
from PyQt5.QtCore import Qt, QEvent

class DigitalBoard(QMainWindow):
    def __init__(self):
        super().__init__()
        loadUi("DigitalBoardMain.ui", self)
        self.setAcceptDrops(True)

        # 给需要拖拽的按钮安装事件过滤器
        self.draggable_buttons = [self.A_1btn, self.A2]
        for btn in self.draggable_buttons:
            btn.installEventFilter(self)
        # 存储每个按钮的拖拽偏移量
        self.drag_offsets = {}

    def eventFilter(self, obj, event):
        if obj not in self.draggable_buttons:
            return super().eventFilter(obj, event)
        
        # 处理鼠标按下事件,记录偏移
        if event.type() == QEvent.MouseButtonPress:
            if event.buttons() == Qt.LeftButton:
                self.drag_offsets[obj] = event.pos()
        # 处理鼠标移动事件,触发拖拽
        elif event.type() == QEvent.MouseMove:
            if event.buttons() != Qt.LeftButton:
                return super().eventFilter(obj, event)
            mime_data = QMimeData()
            drag = QDrag(obj)
            drag.setMimeData(mime_data)
            drag.exec_(Qt.MoveAction)
        
        return super().eventFilter(obj, event)

    def dragEnterEvent(self, event):
        if event.source() in self.draggable_buttons:
            event.acceptProposedAction()

    def dropEvent(self, event):
        if event.source() in self.draggable_buttons:
            target_pos = event.pos() - self.drag_offsets[event.source()]
            event.source().move(target_pos)
            event.acceptProposedAction()

关键提示

  • 不要给主窗口定义多个同名带后缀的事件函数,Qt不会识别这类自定义名称的函数。
  • 记录鼠标按下时的偏移量是为了让按钮移动更贴合鼠标操作,避免按钮瞬移到鼠标坐标的左上角。
  • dragEnterEvent中增加来源判断,可以避免接受无关的拖拽事件,提升交互准确性。

内容的提问来源于stack exchange,提问作者Faa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 16:35:08