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

PyQt5拖拽问题:如何识别当前被拖拽的按钮?

多按钮拖拽异常的解决方案

问题现象

  • 点击Spawn按钮可生成依次命名为Table 1、Table 2的按钮
  • 右键按住拖动按钮可移动,但生成Table 2后,拖拽Table 1时移动的却是Table 2,且Table 1失去拖拽功能

问题根源

mainMenu类的addTable方法用self.btn存储生成的按钮,每次生成新按钮都会覆盖该变量,导致始终仅记录最后一个生成的按钮;同时拖拽的drop逻辑依赖这个全局变量,所以拖拽操作只会作用在最后一个按钮上。

修复方案

将拖拽的完整逻辑封装到barTable类内部,让每个按钮独立处理自身的拖拽事件,无需主窗口记录当前操作的按钮:

  1. 移除mainMenu类中用于存储单个按钮的self.btn变量,以及主窗口的dragEnterEvent和dropEvent方法
  2. 在barTable类中开启拖拽接收,并重写dragEnterEvent和dropEvent,让按钮自己处理拖拽位置更新
  3. 确保每个按钮的拖拽逻辑独立,互不干扰

修改后的完整代码

import sys

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


class mainMenu(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 550, 450)

        self.spawnButton = QPushButton(self)
        self.spawnButton.move(150, 150)
        self.spawnButton.show()
        self.spawnButton.setText('Spawn')
        self.spawnButton.clicked.connect(self.addTable)

    def addTable(self):
        barTable(self)


class barTable(QPushButton):

    allTables = []

    def __init__(self, win):
        super().__init__(win)
        self.setGeometry(300, 300, 60, 50)
        self.allTables.append(self)
        self.setText("Table\n" + str(len(self.allTables)))
        self.setAcceptDrops(True)
        self.show()

    def mouseMoveEvent(self, e):
        if e.buttons() != Qt.RightButton:
            return

        mimeData = QMimeData()
        # 存储拖拽时鼠标相对于按钮左上角的偏移
        mimeData.setData("hotSpot", f"{e.x()},{e.y()}".encode())
        
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())
        drag.exec_(Qt.MoveAction)

    def dragEnterEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        # 读取存储的偏移量
        hot_spot_data = e.mimeData().data("hotSpot").decode().split(",")
        hot_spot = QPoint(int(hot_spot_data[0]), int(hot_spot_data[1]))
        # 计算按钮需要移动到的位置
        position = e.pos() - hot_spot
        self.move(position)
        e.setDropAction(Qt.MoveAction)
        e.accept()


def main():
    app = QApplication(sys.argv)
    ex = mainMenu()
    ex.show()
    app.exec_()


if __name__ == '__main__':
    main()

说明

修改后每个按钮独立处理自身的拖拽逻辑,主窗口不再需要管理按钮的拖拽状态,无论生成多少个按钮,都能正常独立拖拽,不会出现互相干扰的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 14:05:30