Многократное перетаскивание в PyQt4 - PullRequest
1 голос
/ 11 августа 2010

Я не могу найти пример перетаскивания (и удаления) нескольких элементов с помощью 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 (Моя зона сброса):

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)

Любые советы?Спасибо!

1 Ответ

6 голосов
/ 11 августа 2010

Вот полный рабочий пример:

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)))

Если вы не взаимодействуете с 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_()
...