Gia*_*lli 1 python drag-and-drop pyqt pyqt4
我找不到一个用Qt/PyQt拖动(和删除)多个元素的例子; 在我的情况下,我需要从这个QTableView拖动元素:
class DragTable(QTableView):
def __init__(self, parent = None):
super(DragTable, self).__init__(parent)
self.setDragEnabled(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("application/pubmedrecord"):
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.ignore()
def startDrag(self, event):
print type(event)
index = self.indexAt(event.pos())
if not index.isValid():
return
selected = index.row()
bstream = cPickle.dumps(selected)
mimeData = QMimeData()
mimeData.setData("application/pubmedrecord", bstream)
drag = QDrag(self)
drag.setMimeData(mimeData)
pixmap = QPixmap(":/drag.png")
drag.setHotSpot(QPoint(pixmap.width()/3, pixmap.height()/3))
drag.setPixmap(pixmap)
result = drag.start(Qt.MoveAction)
def mouseMoveEvent(self, event):
self.startDrag(event)
Run Code Online (Sandbox Code Playgroud)
对于这个QLabel(我的dropzone):
class TagLabel(QLabel):
def __init__(self, text, color, parent = None):
super(TagLabel, self).__init__(parent)
self.tagColor = color
self.setText(text)
self.setStyleSheet("QLabel { background-color: %s; font-size: 14pt; }" % self.tagColor)
self.defaultStyle = self.styleSheet()
self.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("application/pubmedrecord"):
self.set_bg(True)
event.accept()
else:
event.reject()
def dragLeaveEvent(self, event):
self.set_bg(False)
event.accept()
def dropEvent(self, event):
self.set_bg(False)
data = event.mimeData()
bstream = data.retrieveData("application/pubmedrecord", QVariant.ByteArray)
selected = pickle.loads(bstream.toByteArray())
event.accept()
self.emit(SIGNAL("dropAccepted(PyQt_PyObject)"), (selected, str(self.text()), str(self.tagColor)))
def set_bg(self, active = False):
if active:
style = "QLabel {background: yellow; font-size: 14pt;}"
self.setStyleSheet(style)
else:
self.setStyleSheet(self.defaultStyle)
Run Code Online (Sandbox Code Playgroud)
有小费吗?谢谢!
这是一个完整的工作示例:
from PyQt4 import QtCore, QtGui, Qt
import cPickle
import pickle
Run Code Online (Sandbox Code Playgroud)
你为什么用得cPickle那么好pickle?
class DragTable(QtGui.QTableView):
def __init__(self, parent = None):
super(DragTable, self).__init__(parent)
self.setDragEnabled(True)
self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
Run Code Online (Sandbox Code Playgroud)
您可能想在此处设置选择行为,因为我假设基于行的数据表示.你当然可以改变它.
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("application/pubmedrecord"):
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.ignore()
def startDrag(self, event):
Run Code Online (Sandbox Code Playgroud)
根据事件位置,您的代码在此处仅假定一个索引.对于a QTableView,这是不必要的,因为它已经处理鼠标单击本身.相反,最好依靠Qt 一如既往地为您提供实际需要的信息.在这里,我选择使用selectedIndexes().
indices = self.selectedIndexes()
Run Code Online (Sandbox Code Playgroud)
索引现在是一个QModelIndex实例列表,我选择将其转换为一组行号.QPersistentModelIndex根据您的需要,也可以将这些转换为es 列表.
这里可能会让您大吃一惊的是,索引包含表中所有单元格的索引,而不是所有行,无论选择行为如何.这就是为什么我选择使用set而不是a list.
selected = set()
for index in indices:
selected.add(index.row())
Run Code Online (Sandbox Code Playgroud)
我假设你知道你在那里做什么,我没有动过.
bstream = cPickle.dumps(selected)
mimeData = QtCore.QMimeData()
mimeData.setData("application/pubmedrecord", bstream)
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
pixmap = QtGui.QPixmap(":/drag.png")
drag.setHotSpot(QtCore.QPoint(pixmap.width()/3, pixmap.height()/3))
drag.setPixmap(pixmap)
result = drag.start(QtCore.Qt.MoveAction)
def mouseMoveEvent(self, event):
self.startDrag(event)
class TagLabel(QtGui.QLabel):
def __init__(self, text, color, parent = None):
super(TagLabel, self).__init__(parent)
self.tagColor = color
self.setText(text)
self.setStyleSheet("QLabel { background-color: %s; font-size: 14pt; }" % self.tagColor)
self.defaultStyle = self.styleSheet()
self.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("application/pubmedrecord"):
self.set_bg(True)
event.accept()
else:
event.reject()
def dragLeaveEvent(self, event):
self.set_bg(False)
event.accept()
def dropEvent(self, event):
self.set_bg(False)
data = event.mimeData()
bstream = data.retrieveData("application/pubmedrecord", QtCore.QVariant.ByteArray)
selected = pickle.loads(bstream.toByteArray())
event.accept()
self.emit(QtCore.SIGNAL("dropAccepted(PyQt_PyObject)"), (selected, str(self.text()), str(self.tagColor)))
Run Code Online (Sandbox Code Playgroud)
除非你使用这个信号连接C++代码,否则没有必要在这里添加一个信号参数,你也可以dropAccepted不使用括号,PyQt4会做正确的事情.
def set_bg(self, active = False):
if active:
style = "QLabel {background: yellow; font-size: 14pt;}"
self.setStyleSheet(style)
else:
self.setStyleSheet(self.defaultStyle)
app = QtGui.QApplication([])
l = TagLabel("bla bla bla bla bla bla bla", "red")
l.show()
m = QtGui.QStandardItemModel()
for _ in xrange(4):
m.appendRow([QtGui.QStandardItem(x) for x in ["aap", "noot", "mies"]])
t = DragTable()
t.setModel(m)
t.show()
def h(o):
print "signal handled", o
l.connect(l, QtCore.SIGNAL("dropAccepted(PyQt_PyObject)"), h)
app.exec_()
Run Code Online (Sandbox Code Playgroud)