如何从 QListview 添加图片到 QGraphicsView? (拖放)
How can I add pictures from QListview to QGraphicsView? (with Drag Drop)
首先,我创建了 QListview class。然后,我将项目添加到 QListview 中。之后,我创建了 QGraphicsView class。我想通过拖放将项目的图片(由 QListview 创建)传输到 QGraphicsView。我有个问题。我无法将项目的图片 class 传输到 class。我的代码是这样的
class PartsList(QListView):
def __init__(self, parent):
super().__init__(parent)
self.setGridSize(QSize(108, 80))
self.partsModel = LibraryModel(self)
for i in image_list:
self.partsModel.appendRow(self.__getPartItem(i))
self.setModel(self.partsModel)
self.setViewMode(self.IconMode)
self.setDragDropMode(self.DragOnly)
def __getPartItem(self, name):
part = QStandardItem()
pixmap = QPixmap(name)
part.setData(pixmap, Qt.DecorationRole)
part.setText(name)
part.setEditable(False)
return part
class LibraryModel(QStandardItemModel):
def __init__(self, parent=None):
QStandardItemModel.__init__(self, parent)
self.setColumnCount(1)
def mimeTypes(self):
return ['part/name']
def DropMimeData(self, idxs):
mimedata = QMimeData()
for idx in idxs:
if idx.isValid():
txt = self.data(idx, Qt.DisplayRole)
mimedata.setText(txt)
mimedata.setData('part/name', txt)
return mimedata
QGraphicsView
class SchematicView(QGraphicsView):
def __init__(self, parent):
self.scene = SchematicScene()
super().__init__(self.scene, parent)
self.setSceneRect(0, 0, 1, 1)
def dragEnterEvent(self, event):
event.accept()
def dragMoveEvent(self, event):
event.accept()
def dropEvent(self, event):
pass
没有必要创建一个新的 mimetype,因为模型默认已经有一个 "application/x-qabstractitemmodeldatalist",所以在这种情况下,我将只在 QGraphicsView 中创建一个虚拟模型来接收数据,从而能够在 QGraphicsView 中重用它。
from PyQt5 import QtCore, QtGui, QtWidgets
class PartsList(QtWidgets.QListView):
def __init__(self, parent=None):
super().__init__(parent)
self.setGridSize(QtCore.QSize(108, 80))
self.setViewMode(QtWidgets.QListView.IconMode)
self.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
self._model = QtGui.QStandardItemModel(self)
self.setModel(self._model)
path = QtCore.QStandardPaths.writableLocation(
QtCore.QStandardPaths.PicturesLocation
)
d = QtCore.QDir(path)
formats = [
"*.{}".format(fm.data().decode())
for fm in QtGui.QImageReader.supportedImageFormats()
]
for info in d.entryInfoList(formats, QtCore.QDir.Files):
part = QtGui.QStandardItem(info.filePath())
pixmap = QtGui.QPixmap(info.absoluteFilePath())
part.setData(pixmap, QtCore.Qt.DecorationRole)
self._model.appendRow(part)
class SchematicView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.setSceneRect(0, 0, 1, 1)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat(
"application/x-qabstractitemmodeldatalist"
):
event.acceptProposedAction()
def dragMoveEvent(self, event):
if event.mimeData().hasFormat(
"application/x-qabstractitemmodeldatalist"
):
event.acceptProposedAction()
def dropEvent(self, event):
sp = self.mapToScene(event.pos())
dummy_model = QtGui.QStandardItemModel()
dummy_model.dropMimeData(
event.mimeData(), event.dropAction(), 0, 0, QtCore.QModelIndex()
)
for r in range(dummy_model.rowCount()):
for c in range(dummy_model.columnCount()):
ix = dummy_model.index(r, c)
pixmap = ix.data(QtCore.Qt.DecorationRole)
pixmap_item = self.scene().addPixmap(pixmap)
pixmap_item.setPos(sp)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(w)
pl = PartsList()
sv = SchematicView()
hlay.addWidget(pl)
hlay.addWidget(sv)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
如果您仍想继续使用其他 mimetype,在支持 QListView 等模型的视图中的正确选项是向 mimeData 添加新格式:
from PyQt5 import QtCore, QtGui, QtWidgets
class PartsList(QtWidgets.QListView):
def __init__(self, parent=None):
super().__init__(parent)
self.setGridSize(QtCore.QSize(108, 80))
self.setViewMode(QtWidgets.QListView.IconMode)
self.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
self._model = LibraryModel(self)
self.setModel(self._model)
path = QtCore.QStandardPaths.writableLocation(
QtCore.QStandardPaths.PicturesLocation
)
d = QtCore.QDir(path)
formats = [
"*.{}".format(fm.data().decode())
for fm in QtGui.QImageReader.supportedImageFormats()
]
for info in d.entryInfoList(formats, QtCore.QDir.Files):
part = self.__getPartItem(info.filePath())
self._model.appendRow(part)
def __getPartItem(self, name):
part = QtGui.QStandardItem()
pixmap = QtGui.QPixmap(name)
part.setData(pixmap, QtCore.Qt.DecorationRole)
part.setText(name)
part.setEditable(False)
return part
class LibraryModel(QtGui.QStandardItemModel):
def __init__(self, parent=None):
super().__init__(parent)
self.setColumnCount(1)
def mimeTypes(self):
return super().mimeTypes() + ["part/name"]
def mimeData(self, indexes):
data = super().mimeData(indexes)
encoded = QtCore.QByteArray()
stream = QtCore.QDataStream(encoded, QtCore.QIODevice.WriteOnly)
for ix in indexes:
stream << ix.data(QtCore.Qt.DecorationRole)
data.setData("part/name", encoded)
return data
class SchematicView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.setSceneRect(0, 0, 1, 1)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("part/name"):
event.acceptProposedAction()
def dragMoveEvent(self, event):
if event.mimeData().hasFormat("part/name"):
event.acceptProposedAction()
def dropEvent(self, event):
sp = self.mapToScene(event.pos())
fmt = "part/name"
data = event.mimeData()
if data.hasFormat(fmt):
encoded = data.data(fmt)
stream = QtCore.QDataStream(encoded, QtCore.QIODevice.ReadOnly)
pixmap = QtGui.QPixmap()
while not stream.atEnd():
stream >> pixmap
pixmap_item = self.scene().addPixmap(pixmap)
pixmap_item.setPos(sp)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(w)
pl = PartsList()
sv = SchematicView()
hlay.addWidget(pl)
hlay.addWidget(sv)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
首先,我创建了 QListview class。然后,我将项目添加到 QListview 中。之后,我创建了 QGraphicsView class。我想通过拖放将项目的图片(由 QListview 创建)传输到 QGraphicsView。我有个问题。我无法将项目的图片 class 传输到 class。我的代码是这样的
class PartsList(QListView):
def __init__(self, parent):
super().__init__(parent)
self.setGridSize(QSize(108, 80))
self.partsModel = LibraryModel(self)
for i in image_list:
self.partsModel.appendRow(self.__getPartItem(i))
self.setModel(self.partsModel)
self.setViewMode(self.IconMode)
self.setDragDropMode(self.DragOnly)
def __getPartItem(self, name):
part = QStandardItem()
pixmap = QPixmap(name)
part.setData(pixmap, Qt.DecorationRole)
part.setText(name)
part.setEditable(False)
return part
class LibraryModel(QStandardItemModel):
def __init__(self, parent=None):
QStandardItemModel.__init__(self, parent)
self.setColumnCount(1)
def mimeTypes(self):
return ['part/name']
def DropMimeData(self, idxs):
mimedata = QMimeData()
for idx in idxs:
if idx.isValid():
txt = self.data(idx, Qt.DisplayRole)
mimedata.setText(txt)
mimedata.setData('part/name', txt)
return mimedata
QGraphicsView
class SchematicView(QGraphicsView):
def __init__(self, parent):
self.scene = SchematicScene()
super().__init__(self.scene, parent)
self.setSceneRect(0, 0, 1, 1)
def dragEnterEvent(self, event):
event.accept()
def dragMoveEvent(self, event):
event.accept()
def dropEvent(self, event):
pass
没有必要创建一个新的 mimetype,因为模型默认已经有一个 "application/x-qabstractitemmodeldatalist",所以在这种情况下,我将只在 QGraphicsView 中创建一个虚拟模型来接收数据,从而能够在 QGraphicsView 中重用它。
from PyQt5 import QtCore, QtGui, QtWidgets
class PartsList(QtWidgets.QListView):
def __init__(self, parent=None):
super().__init__(parent)
self.setGridSize(QtCore.QSize(108, 80))
self.setViewMode(QtWidgets.QListView.IconMode)
self.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
self._model = QtGui.QStandardItemModel(self)
self.setModel(self._model)
path = QtCore.QStandardPaths.writableLocation(
QtCore.QStandardPaths.PicturesLocation
)
d = QtCore.QDir(path)
formats = [
"*.{}".format(fm.data().decode())
for fm in QtGui.QImageReader.supportedImageFormats()
]
for info in d.entryInfoList(formats, QtCore.QDir.Files):
part = QtGui.QStandardItem(info.filePath())
pixmap = QtGui.QPixmap(info.absoluteFilePath())
part.setData(pixmap, QtCore.Qt.DecorationRole)
self._model.appendRow(part)
class SchematicView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.setSceneRect(0, 0, 1, 1)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat(
"application/x-qabstractitemmodeldatalist"
):
event.acceptProposedAction()
def dragMoveEvent(self, event):
if event.mimeData().hasFormat(
"application/x-qabstractitemmodeldatalist"
):
event.acceptProposedAction()
def dropEvent(self, event):
sp = self.mapToScene(event.pos())
dummy_model = QtGui.QStandardItemModel()
dummy_model.dropMimeData(
event.mimeData(), event.dropAction(), 0, 0, QtCore.QModelIndex()
)
for r in range(dummy_model.rowCount()):
for c in range(dummy_model.columnCount()):
ix = dummy_model.index(r, c)
pixmap = ix.data(QtCore.Qt.DecorationRole)
pixmap_item = self.scene().addPixmap(pixmap)
pixmap_item.setPos(sp)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(w)
pl = PartsList()
sv = SchematicView()
hlay.addWidget(pl)
hlay.addWidget(sv)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
如果您仍想继续使用其他 mimetype,在支持 QListView 等模型的视图中的正确选项是向 mimeData 添加新格式:
from PyQt5 import QtCore, QtGui, QtWidgets
class PartsList(QtWidgets.QListView):
def __init__(self, parent=None):
super().__init__(parent)
self.setGridSize(QtCore.QSize(108, 80))
self.setViewMode(QtWidgets.QListView.IconMode)
self.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
self._model = LibraryModel(self)
self.setModel(self._model)
path = QtCore.QStandardPaths.writableLocation(
QtCore.QStandardPaths.PicturesLocation
)
d = QtCore.QDir(path)
formats = [
"*.{}".format(fm.data().decode())
for fm in QtGui.QImageReader.supportedImageFormats()
]
for info in d.entryInfoList(formats, QtCore.QDir.Files):
part = self.__getPartItem(info.filePath())
self._model.appendRow(part)
def __getPartItem(self, name):
part = QtGui.QStandardItem()
pixmap = QtGui.QPixmap(name)
part.setData(pixmap, QtCore.Qt.DecorationRole)
part.setText(name)
part.setEditable(False)
return part
class LibraryModel(QtGui.QStandardItemModel):
def __init__(self, parent=None):
super().__init__(parent)
self.setColumnCount(1)
def mimeTypes(self):
return super().mimeTypes() + ["part/name"]
def mimeData(self, indexes):
data = super().mimeData(indexes)
encoded = QtCore.QByteArray()
stream = QtCore.QDataStream(encoded, QtCore.QIODevice.WriteOnly)
for ix in indexes:
stream << ix.data(QtCore.Qt.DecorationRole)
data.setData("part/name", encoded)
return data
class SchematicView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.setSceneRect(0, 0, 1, 1)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("part/name"):
event.acceptProposedAction()
def dragMoveEvent(self, event):
if event.mimeData().hasFormat("part/name"):
event.acceptProposedAction()
def dropEvent(self, event):
sp = self.mapToScene(event.pos())
fmt = "part/name"
data = event.mimeData()
if data.hasFormat(fmt):
encoded = data.data(fmt)
stream = QtCore.QDataStream(encoded, QtCore.QIODevice.ReadOnly)
pixmap = QtGui.QPixmap()
while not stream.atEnd():
stream >> pixmap
pixmap_item = self.scene().addPixmap(pixmap)
pixmap_item.setPos(sp)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(w)
pl = PartsList()
sv = SchematicView()
hlay.addWidget(pl)
hlay.addWidget(sv)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())