Я не могу найти пример перетаскивания (и удаления) нескольких элементов с помощью 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)
В эту QLabel (My 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)
Какие-нибудь советы? Спасибо!
Вот полный рабочий пример:
from PyQt4 import QtCore, QtGui, Qt
import cPickle
import pickle
Почему вы используете cPickle
, а также pickle
?
class DragTable(QtGui.QTableView):
def __init__(self, parent = None):
super(DragTable, self).__init__(parent)
self.setDragEnabled(True)
self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
Вероятно, вы захотите установить здесь поведение выбора, потому что я предполагаю представление данных на основе строк. Вы можете, конечно, изменить это.
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("application/pubmedrecord"):
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.ignore()
def startDrag(self, event):
В вашем коде предполагается только один индекс, основанный на позиции события. Для QTableView
это необязательно, поскольку он уже обрабатывает щелчок мыши. Вместо этого лучше зависеть от Qt, чтобы предоставить вам необходимую вам информацию, как всегда. Здесь я решил использовать selectedIndexes()
.
indices = self.selectedIndexes()
Индексы теперь представляют собой список экземпляров QModelIndex
, которые я решил преобразовать в набор номеров строк. Также возможно преобразовать их в список QPersistentModelIndex
es, в зависимости от ваших потребностей.
Одна вещь, которая может вас удивить, состоит в том, что индексы содержат индексы для всех ячеек в таблице, а не все строки, независимо от поведения выбора. Поэтому я решил использовать set
вместо list
.
selected = set()
for index in indices:
selected.add(index.row())
Я оставил остальное нетронутым, предполагая, что вы знаете, что вы там делаете.
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)))
Если вы не взаимодействуете с С++-кодом с этим сигналом, нет необходимости добавлять здесь аргумент сигнала, вы также можете использовать 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_()