PyQt5组件间拖放时DropEvent未触发问题求助
解决拖拽时组件间区域DropEvent不触发的问题
我之前遇到过完全一样的情况,你的问题根源很明确:虽然给MyQDialog设置了setAcceptDrops(True),但没有实现dragEnterEvent和dragMoveEvent。当鼠标拖拽到组件之间的空白区域(属于MyQDialog范围但没被MyFrame覆盖)时,默认的事件处理会拒绝这些拖拽事件,导致松开鼠标时系统认为这个区域不接受放置,自然不会触发dropEvent。
简单修复方案
只需要给MyQDialog补上dragEnterEvent和dragMoveEvent的实现,让整个窗口的所有区域都认可拖拽操作就行。另外还有个小优化点可以顺手调整,下面是完整的修改后代码:
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'DS_Test.ui' # # Created by: PyQt5 UI code generator 5.15.7 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtGui import QDragEnterEvent, QDropEvent class MyButton(QtWidgets.QPushButton): def mouseMoveEvent(self, event): btn_img = self.grab() painter = QtGui.QPainter(btn_img) painter.setCompositionMode(painter.CompositionMode_DestinationIn) painter.fillRect(btn_img.rect(), QtGui.QColor(0, 0, 0, 150)) painter.end() data = QtCore.QMimeData() drag = QtGui.QDrag(self) drag.setMimeData(data) drag.setPixmap(btn_img) drag.setHotSpot(event.pos()) self._pos = event.pos() # 执行拖拽,这里不需要调用super,默认的mouseMoveEvent不处理拖拽逻辑 drag.exec_(QtCore.Qt.CopyAction) class MyFrame(QtWidgets.QFrame): def __init__(self, parent): super().__init__(parent) self.setAcceptDrops(True) def dragEnterEvent(self, e: QDragEnterEvent): e.accept() def dragMoveEvent(self, e): e.accept() def dropEvent(self, e: QDropEvent): self.parent().dropEvent(e) class MyQDialog(QtWidgets.QDialog): def __init__(self): super().__init__() self.setAcceptDrops(True) def dragEnterEvent(self, e: QDragEnterEvent): # 接受所有进入窗口的拖拽事件 e.accept() def dragMoveEvent(self, e): # 允许拖拽在窗口内任意区域移动 e.accept() def dropEvent(self, e: QDropEvent): print("dropEvent - is done") # 这里可以添加向服务器发送消息的逻辑 e.accept() class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(1051, 800) self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) self.verticalLayout.setObjectName("verticalLayout") self.horizontalFrame = MyFrame(Dialog) self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));") self.horizontalFrame.setObjectName("horizontalFrame") self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame) self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.pushButton_3 = MyButton(self.horizontalFrame) self.pushButton_3.setObjectName("pushButton_3") self.horizontalLayout_6.addWidget(self.pushButton_3) self.pushButton_2 = MyButton(self.horizontalFrame) self.pushButton_2.setObjectName("pushButton_2") self.horizontalLayout_6.addWidget(self.pushButton_2) self.pushButton = MyButton(self.horizontalFrame) self.pushButton.setObjectName("pushButton") self.horizontalLayout_6.addWidget(self.pushButton) self.verticalLayout.addWidget(self.horizontalFrame) self.horizontalFrame_2 = MyFrame(Dialog) self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));") self.horizontalFrame_2.setObjectName("horizontalFrame_2") self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2) self.horizontalLayout_7.setObjectName("horizontalLayout_7") self.verticalLayout.addWidget(self.horizontalFrame_2) self.horizontalFrame_3 = MyFrame(Dialog) self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));") self.horizontalFrame_3.setObjectName("horizontalFrame_3") self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3) self.horizontalLayout_8.setObjectName("horizontalLayout_8") self.verticalLayout.addWidget(self.horizontalFrame_3) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.pushButton_3.setText(_translate("Dialog", "PushButton")) self.pushButton_2.setText(_translate("Dialog", "PushButton")) self.pushButton.setText(_translate("Dialog", "PushButton")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) Dialog = MyQDialog() ui = Ui_Dialog() ui.setupUi(Dialog) Dialog.show() sys.exit(app.exec_())
修改细节说明
- 给MyQDialog添加事件处理:新增了
dragEnterEvent和dragMoveEvent,在这两个方法里调用e.accept(),相当于告诉系统“这个区域可以接受拖拽”,这样不管鼠标在窗口内哪个位置松开,都会触发dropEvent。 - 移除MyButton中的super调用:
drag.exec_()是阻塞执行的,拖拽完成后才会继续往下走,而默认的mouseMoveEvent对拖拽逻辑没有帮助,所以去掉这个调用避免不必要的事件处理。
这样修改后,你就可以放心地在dropEvent里添加向服务器发送消息的代码了,每次拖拽结束都会触发这个方法~
内容的提问来源于stack exchange,提问作者Игорь Платонов
相关产品推荐
相关产品推荐

