[英]Qt: Prevent drag-and-drop on child widgets and show forbidden cursor
我想在一些自定義小部件中啟用拖放功能,以允許在布局中重新排序和重新排列小部件。 基本功能正在運行,但我想防止將小部件放在自身或自身的孩子上。 這在dropEvent
方法中很簡單,但我找不到在拖動時也顯示“禁止”cursor 的方法,以便用戶知道不允許放置。
下面的例子展示了一個測試實現,其中“一”到“五”的小部件可以拖放(不會發生重新排列,只會在終端上打印一條消息,您可能需要按Ctrl或其他東西來啟動一個拖)。 問題行是dragEnterEvent
方法中的第一個ev.accept()
。 通過接受該事件,cursor 顯示在“允許的”state(對我來說是一只手)中。 例如,嘗試將“一”拖放到“三”上似乎是允許的,但不會發生任何事情。 但是,忽略事件會導致事件傳播到父級,因此在這種情況下,將“三”拖放到“三”上會導致“一”得到下降。 設置WA_NoMousePropagation
屬性似乎沒有任何區別。
所以,我需要的是一種“接受”事件的方法,這樣它就不會傳播到父級,但仍然顯示“禁止”cursor,就好像沒有人接受這個事件一樣。 有任何想法嗎?
#!/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_() )
可能最簡單的方法是始終在dragEnterEvent
中接受事件,並且在事件源是self
的祖先時在dragMoveEvent
中忽略它,即
def dragEnterEvent(self, ev):
ev.accept()
def dragMoveEvent(self, ev):
item = ev.source()
if item.isAncestorOf(self):
ev.ignore()
通過忽略dragMoveEvent
中的事件,您也不需要簽入dropEvent
並且可以簡單地執行
def dropEvent(self, ev):
print('Dropped of', self.layout().itemAt(0).widget().text())
ev.accept()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.