【发布时间】:2020-05-05 14:58:57
【问题描述】:
我想在一些自定义小部件中启用拖放功能,以允许在布局中重新排序和重新排列小部件。基本功能正在运行,但我想防止将小部件放在自身或自身的孩子上。这在dropEvent 方法中很简单,但我找不到在拖动时也显示“禁止”光标的方法,以便用户知道不允许放置。
下面的例子展示了一个测试实现,其中小部件“一”到“五”可以拖放(不会发生重新排列,只会在终端上打印一条消息,您可能需要按Ctrl或其他方式)启动拖动)。问题行是dragEnterEvent 方法中的第一个ev.accept()。通过接受该事件,光标显示为“允许”状态(对我来说是一只手)。例如,尝试将“一”拖放到“三”上似乎是允许的,但不会发生任何事情。但是,忽略事件会导致事件传播到父级,因此在这种情况下,将“三”拖放到“三”上会导致“一”得到下降。设置WA_NoMousePropagation 属性似乎没有任何区别。
所以,我需要一种“接受”事件的方法,这样它就不会传播到父级,但仍然显示“禁止”光标,就好像没有人接受事件一样。有什么想法吗?
#!/usr/bin/env python3
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class WidgetMimeData(QtCore.QMimeData):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.itemObject = None
def hasFormat(self, mime):
if (self.itemObject and (mime == 'widgetitem')):
return True
return super().hasFormat(mime)
def setItem(self, obj):
self.itemObject = obj
def item(self):
return self.itemObject
class DraggableWidget(QGroupBox):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
self.setLayout(layout)
self.setAcceptDrops(True)
def addWidget(self, widget):
return self.layout().addWidget(widget)
def mouseMoveEvent(self, ev):
pixmap = QPixmap(self.size())
pixmap.fill(QtCore.Qt.transparent)
painter = QPainter()
painter.begin(pixmap)
painter.setOpacity(0.8)
painter.drawPixmap(0, 0, self.grab())
painter.end()
drag = QDrag(self)
mimedata = WidgetMimeData()
mimedata.setItem(self)
drag.setMimeData(mimedata)
drag.setPixmap(pixmap)
drag.setHotSpot(ev.pos())
drag.exec_(QtCore.Qt.MoveAction)
def dragEnterEvent(self, ev):
item = ev.mimeData().item()
if item.isAncestorOf(self):
#ev.ignore()
ev.accept()
else:
ev.accept()
def dropEvent(self, ev):
item = ev.mimeData().item()
if not item.isAncestorOf(self):
print('dropped on', self.layout().itemAt(0).widget().text())
ev.accept()
class HelloWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
w1 = DraggableWidget()
w1.addWidget(QLabel('One'))
w2 = DraggableWidget()
w2.addWidget(QLabel('Two'))
w3 = DraggableWidget()
w3.addWidget(QLabel('Three'))
w4 = DraggableWidget()
w4.addWidget(QLabel('Four'))
w5 = DraggableWidget()
w5.addWidget(QLabel('Five'))
w1.addWidget(w3)
w1.addWidget(w4)
w2.addWidget(w5)
layout = QVBoxLayout()
layout.addWidget(w1)
layout.addWidget(w2)
layout.addStretch(1)
centralWidget = QWidget(self)
centralWidget.setLayout(layout)
self.setCentralWidget(centralWidget)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = HelloWindow()
mainWin.show()
sys.exit( app.exec_() )
【问题讨论】:
标签: python pyqt drag-and-drop pyqt5