QGraphicsView无法拖放两次
QGraphicsView unable to drag and drop twice
我试图通过将图像拖到 QGraphicsView 来读取图像。我已经完成了,这是代码:
ui.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>772</width>
<height>671</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="DropGraphicsView" name="graphicsView"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Run</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>DropGraphicsView</class>
<extends>QGraphicsView</extends>
<header>DropGraphicsView</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
DropGraphicsView.py
import warnings
import numpy as np
from PyQt5.QtWidgets import QGraphicsView, QGraphicsPixmapItem, QGraphicsScene
from PyQt5.QtGui import QPixmap, QImage
class DropGraphicsView(QGraphicsView):
def __init__(self, parent):
super(DropGraphicsView, self).__init__(parent)
self.setAcceptDrops(True)
self.image_path = None # to save the path of the image
def dragEnterEvent(self, event):
print("dragEnterEvent:") # called in the first drag, not in the second, why?
if event.mimeData().hasUrls():
event.accept()
print("accepted")
else:
event.ignore()
print("ignored")
def dropEvent(self, event):
self._get_image_path(event) # get the path of image
self.show_image(self.image_path) # show the image
print(self.acceptDrops()) # still True when printed
def _get_image_path(self, event):
urls = event.mimeData().urls()
image_path = urls[0].toString().replace('file:///', '')
print(image_path)
self.image_path = image_path
def show_image(self, image_path):
# read the image
if isinstance(image_path, str):
frame = QImage(image_path)
elif isinstance(image_path, np.ndarray):
frame = QImage(image_path, image_path.shape[1], image_path.shape[0],
QImage.Format_RGB888)
else:
warnings.warn("wrong type")
return
if frame is not None:
# scale the image
size = self.size()
size.setWidth(size.width() - 2)
size.setHeight(size.height() - 2)
frame = frame.scaled(size)
# show the image
pix = QPixmap.fromImage(frame)
self.item = QGraphicsPixmapItem(pix) # 创建像素图元
self.scene = QGraphicsScene() # 创建场景
self.scene.addItem(self.item)
self.setScene(self.scene)
self.show()
main.py
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication
UI_path = "ui.ui"
class Main:
def __init__(self):
self.ui = uic.loadUi(UI_path)
self.ui.pushButton.clicked.connect(self._run)
def _run(self):
# do something
if __name__ == '__main__':
app = QApplication([])
main = Main()
main.ui.show()
app.exec_()
一切正常,可以显示掉落的图像。但是一个镜像被drop之后,其他的image就不能再被drop了。第二次拖动时未调用 dragEnterEvent。为什么?
最后我自己解决了我的问题
问题是 DropGraphicsView.show() 中使用的 QGraphicsScene 不支持拖放。所以显示图片后,DropGraphicsView 区域无法接收到拖放事件。
解决方案是继承 QGraphicsScene:
DropGraphicsScene.py
from PyQt5.QtWidgets import QGraphicsScene
class DropGraphicsScene(QGraphicsScene):
def __init__(self):
super(QGraphicsScene, self).__init__()
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
event.accept()
def dragMoveEvent(self, e):
e.acceptProposedAction()
并在 DropGraphicsView.py 中使用 DropGraphicsScene 而不是 QGraphicsScene:
import warnings
import numpy as np
from PyQt5.QtWidgets import QGraphicsView, QGraphicsPixmapItem, QGraphicsScene
from PyQt5.QtGui import QPixmap, QImage
import DropGraphicsScene
class DropGraphicsView(QGraphicsView):
def __init__(self, parent):
super(DropGraphicsView, self).__init__(parent)
self.setAcceptDrops(True)
self.image_path = None # to save the path of the image
def dragEnterEvent(self, event):
print("dragEnterEvent:") # called in the first drag, not in the second, why?
if event.mimeData().hasUrls():
event.accept()
print("accepted")
else:
event.ignore()
print("ignored")
def dropEvent(self, event):
self._get_image_path(event) # get the path of image
self.show_image(self.image_path) # show the image
print(self.acceptDrops()) # still True when printed
def _get_image_path(self, event):
urls = event.mimeData().urls()
image_path = urls[0].toString().replace('file:///', '')
print(image_path)
self.image_path = image_path
def show_image(self, image_path):
# read the image
if isinstance(image_path, str):
frame = QImage(image_path)
elif isinstance(image_path, np.ndarray):
frame = QImage(image_path, image_path.shape[1], image_path.shape[0],
QImage.Format_RGB888)
else:
warnings.warn("wrong type")
return
if frame is not None:
# scale the image
size = self.size()
size.setWidth(size.width() - 2)
size.setHeight(size.height() - 2)
frame = frame.scaled(size)
# show the image
pix = QPixmap.fromImage(frame)
self.item = QGraphicsPixmapItem(pix)
self.scene = DropGraphicsScene.DropGraphicsScene()
self.scene.addItem(self.item)
self.setScene(self.scene)
self.show()
我试图通过将图像拖到 QGraphicsView 来读取图像。我已经完成了,这是代码:
ui.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>772</width>
<height>671</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="DropGraphicsView" name="graphicsView"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Run</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>DropGraphicsView</class>
<extends>QGraphicsView</extends>
<header>DropGraphicsView</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
DropGraphicsView.py
import warnings
import numpy as np
from PyQt5.QtWidgets import QGraphicsView, QGraphicsPixmapItem, QGraphicsScene
from PyQt5.QtGui import QPixmap, QImage
class DropGraphicsView(QGraphicsView):
def __init__(self, parent):
super(DropGraphicsView, self).__init__(parent)
self.setAcceptDrops(True)
self.image_path = None # to save the path of the image
def dragEnterEvent(self, event):
print("dragEnterEvent:") # called in the first drag, not in the second, why?
if event.mimeData().hasUrls():
event.accept()
print("accepted")
else:
event.ignore()
print("ignored")
def dropEvent(self, event):
self._get_image_path(event) # get the path of image
self.show_image(self.image_path) # show the image
print(self.acceptDrops()) # still True when printed
def _get_image_path(self, event):
urls = event.mimeData().urls()
image_path = urls[0].toString().replace('file:///', '')
print(image_path)
self.image_path = image_path
def show_image(self, image_path):
# read the image
if isinstance(image_path, str):
frame = QImage(image_path)
elif isinstance(image_path, np.ndarray):
frame = QImage(image_path, image_path.shape[1], image_path.shape[0],
QImage.Format_RGB888)
else:
warnings.warn("wrong type")
return
if frame is not None:
# scale the image
size = self.size()
size.setWidth(size.width() - 2)
size.setHeight(size.height() - 2)
frame = frame.scaled(size)
# show the image
pix = QPixmap.fromImage(frame)
self.item = QGraphicsPixmapItem(pix) # 创建像素图元
self.scene = QGraphicsScene() # 创建场景
self.scene.addItem(self.item)
self.setScene(self.scene)
self.show()
main.py
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication
UI_path = "ui.ui"
class Main:
def __init__(self):
self.ui = uic.loadUi(UI_path)
self.ui.pushButton.clicked.connect(self._run)
def _run(self):
# do something
if __name__ == '__main__':
app = QApplication([])
main = Main()
main.ui.show()
app.exec_()
一切正常,可以显示掉落的图像。但是一个镜像被drop之后,其他的image就不能再被drop了。第二次拖动时未调用 dragEnterEvent。为什么?
最后我自己解决了我的问题
问题是 DropGraphicsView.show() 中使用的 QGraphicsScene 不支持拖放。所以显示图片后,DropGraphicsView 区域无法接收到拖放事件。
解决方案是继承 QGraphicsScene: DropGraphicsScene.py
from PyQt5.QtWidgets import QGraphicsScene
class DropGraphicsScene(QGraphicsScene):
def __init__(self):
super(QGraphicsScene, self).__init__()
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
event.accept()
def dragMoveEvent(self, e):
e.acceptProposedAction()
并在 DropGraphicsView.py 中使用 DropGraphicsScene 而不是 QGraphicsScene:
import warnings
import numpy as np
from PyQt5.QtWidgets import QGraphicsView, QGraphicsPixmapItem, QGraphicsScene
from PyQt5.QtGui import QPixmap, QImage
import DropGraphicsScene
class DropGraphicsView(QGraphicsView):
def __init__(self, parent):
super(DropGraphicsView, self).__init__(parent)
self.setAcceptDrops(True)
self.image_path = None # to save the path of the image
def dragEnterEvent(self, event):
print("dragEnterEvent:") # called in the first drag, not in the second, why?
if event.mimeData().hasUrls():
event.accept()
print("accepted")
else:
event.ignore()
print("ignored")
def dropEvent(self, event):
self._get_image_path(event) # get the path of image
self.show_image(self.image_path) # show the image
print(self.acceptDrops()) # still True when printed
def _get_image_path(self, event):
urls = event.mimeData().urls()
image_path = urls[0].toString().replace('file:///', '')
print(image_path)
self.image_path = image_path
def show_image(self, image_path):
# read the image
if isinstance(image_path, str):
frame = QImage(image_path)
elif isinstance(image_path, np.ndarray):
frame = QImage(image_path, image_path.shape[1], image_path.shape[0],
QImage.Format_RGB888)
else:
warnings.warn("wrong type")
return
if frame is not None:
# scale the image
size = self.size()
size.setWidth(size.width() - 2)
size.setHeight(size.height() - 2)
frame = frame.scaled(size)
# show the image
pix = QPixmap.fromImage(frame)
self.item = QGraphicsPixmapItem(pix)
self.scene = DropGraphicsScene.DropGraphicsScene()
self.scene.addItem(self.item)
self.setScene(self.scene)
self.show()