Reputation: 43
I'm trying to read an image by drag it to a QGraphicsView. I've done it and here is the code:
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_()
Everything works fine and the image dropped can be showed. But after an image is dropped, other images can't be dropped. The dragEnterEvent is not called in the second drag. Why?
Upvotes: 0
Views: 217
Reputation: 43
Finally, I solved my question by myself.
The problem is that the QGraphicsScene used in DropGraphicsView.show() doesn't support drag and drop. So after an image is shown, the DropGraphicsView area can't receive a drop event.
The solution is to subclass the 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()
And use DropGraphicsScene instead of QGraphicsScene in DropGraphicsView.py:
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()
Upvotes: 2