Python 单击相应的QGraphicsPixmapItem时如何打开图像?
我正在使用Python 单击相应的QGraphicsPixmapItem时如何打开图像?,python,pyqt5,qgraphicsscene,qgraphicspixmapitem,Python,Pyqt5,Qgraphicsscene,Qgraphicspixmapitem,我正在使用qgraphicscene和QGraphicsPixmapItem(下面的代码)构建一个GUI,用于在网格中显示照片(来自文件夹)。现在我想在单击其中一个qgraphicspixmapitem时打开相应的原始图像。如果我在qgraphicscene中单击,我会重写MousePressEvent并使程序执行“操作”,但现在我想知道如何检索单击哪个项目的信息以打开相应的图像 import sys from PyQt5 import QtWidgets, QtCore from PyQt5.
qgraphicscene
和QGraphicsPixmapItem
(下面的代码)构建一个GUI,用于在网格中显示照片(来自文件夹)。现在我想在单击其中一个qgraphicspixmapitem
时打开相应的原始图像。如果我在qgraphicscene
中单击,我会重写MousePressEvent并使程序执行“操作”,但现在我想知道如何检索单击哪个项目的信息以打开相应的图像
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QGraphicsPixmapItem
from PyQt5.QtCore import Qt, QRect
from PyQt5.QtGui import QPixmap
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.showMaximized()
self.central()
def central(self):
self.scene = QtWidgets.QGraphicsScene(QtCore.QRectF(0, 0, 1080, 1000), self)
self.graphicsview = QtWidgets.QGraphicsView(self.scene)
self.setCentralWidget(self.graphicsview)
self.resize(1000, 1000)
list = ['./images/1.JPG', './images/2.JPG', './images/3.JPG', './images/4.JPG',
'./images/5.JPG', './images/6.JPG', './images/7.JPG', './images/8.JPG']
self.t_list = []
for n in range(len(list)):
self.label = QLabel()
self.u_pixmap = QPixmap(list[n])
imgsize = min(self.u_pixmap.width(), self.u_pixmap.height())
rect = QRect(
int((self.u_pixmap.width() - imgsize) / 2),
int((self.u_pixmap.height() - imgsize) / 2), imgsize, imgsize)
self.v_pixmap = self.u_pixmap.copy(rect)
self.pixmap = self.v_pixmap.scaled(200, 200, Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.item = QGraphicsPixmapItem()
self.item.setPixmap(self.pixmap)
self.scene.addItem(self.item)
g = 210
a = 5
y = int(n/a)
x = n - (y * a)
self.item.setOffset(x * g, y * g)
def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
print("item clicked")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
首先,在使用循环时,连续设置相同的实例属性是完全无用的:每次循环时,
self.u_pixmap
,self.pixmap
和self.item
都将被覆盖
然后,总是从当前关注的对象(或小部件)捕获鼠标事件;由于您的mousePressEvent
覆盖是针对QMainWindow实例的,而当前的焦点对象是QGraphicsView,因此您永远不会获得任何鼠标事件,因为图形视图将捕获它
最后,为了实现您想要的,您需要为图形项实现mousePressEvent
,但是由于QGraphicsItem不是QObject子类,因此如果不使用自定义的“信号代理”,就无法直接创建新信号
作为旁注,使用self.resize()
也完全没有用,因为您使用的是self.showmized()
这是您试图实现的目标的可能实现:
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QGraphicsPixmapItem,
QGraphicsView, QGraphicsScene, QLabel)
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QRectF
from PyQt5.QtGui import QPixmap
class SignalProxy(QObject):
clicked = pyqtSignal(object)
class ClickablePixmapItem(QGraphicsPixmapItem):
def __init__(self, source):
super().__init__()
self.source = source
self.setPixmap(source.scaled(200, 200,
Qt.KeepAspectRatio, Qt.SmoothTransformation))
self._signalProxy = SignalProxy()
self.clicked = self._signalProxy.clicked
def mousePressEvent(self, event):
self.clicked.emit(self)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.showMaximized()
self.central()
self.windows = {}
def central(self):
self.scene = QGraphicsScene(QRectF(0, 0, 1080, 1000), self)
self.graphicsview = QGraphicsView(self.scene)
self.setCentralWidget(self.graphicsview)
self.resize(1000, 1000)
list = ['./images/1.JPG', './images/2.JPG', './images/3.JPG', './images/4.JPG',
'./images/5.JPG', './images/6.JPG', './images/7.JPG', './images/8.JPG']
self.t_list = []
for n in range(len(list)):
item = ClickablePixmapItem(QPixmap(list[n]))
item.clicked.connect(self.imageClicked)
self.scene.addItem(item)
g = 210
a = 5
y = int(n/a)
x = n - (y * a)
item.setOffset(x * g, y * g)
def imageClicked(self, item):
window = self.windows.get(item)
if not window:
window = self.windows[item] = QLabel()
window.setPixmap(item.source)
window.show()
window.activateWindow()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
提示:避免混合导入“样式”。您可以导入模块(
从PyQt5导入qtwidts,QtCore
)或相关类(从PyQt5.qtwidts导入(…)
)。首先,在使用循环时,连续设置相同的实例属性是完全没有用的:每次循环时,self.u pixmap
,self.pixmap
和self.item
将被覆盖
然后,总是从当前关注的对象(或小部件)捕获鼠标事件;由于您的mousePressEvent
覆盖是针对QMainWindow实例的,而当前的焦点对象是QGraphicsView,因此您永远不会获得任何鼠标事件,因为图形视图将捕获它
最后,为了实现您想要的,您需要为图形项实现mousePressEvent
,但是由于QGraphicsItem不是QObject子类,因此如果不使用自定义的“信号代理”,就无法直接创建新信号
作为旁注,使用self.resize()
也完全没有用,因为您使用的是self.showmized()
这是您试图实现的目标的可能实现:
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QGraphicsPixmapItem,
QGraphicsView, QGraphicsScene, QLabel)
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QRectF
from PyQt5.QtGui import QPixmap
class SignalProxy(QObject):
clicked = pyqtSignal(object)
class ClickablePixmapItem(QGraphicsPixmapItem):
def __init__(self, source):
super().__init__()
self.source = source
self.setPixmap(source.scaled(200, 200,
Qt.KeepAspectRatio, Qt.SmoothTransformation))
self._signalProxy = SignalProxy()
self.clicked = self._signalProxy.clicked
def mousePressEvent(self, event):
self.clicked.emit(self)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.showMaximized()
self.central()
self.windows = {}
def central(self):
self.scene = QGraphicsScene(QRectF(0, 0, 1080, 1000), self)
self.graphicsview = QGraphicsView(self.scene)
self.setCentralWidget(self.graphicsview)
self.resize(1000, 1000)
list = ['./images/1.JPG', './images/2.JPG', './images/3.JPG', './images/4.JPG',
'./images/5.JPG', './images/6.JPG', './images/7.JPG', './images/8.JPG']
self.t_list = []
for n in range(len(list)):
item = ClickablePixmapItem(QPixmap(list[n]))
item.clicked.connect(self.imageClicked)
self.scene.addItem(item)
g = 210
a = 5
y = int(n/a)
x = n - (y * a)
item.setOffset(x * g, y * g)
def imageClicked(self, item):
window = self.windows.get(item)
if not window:
window = self.windows[item] = QLabel()
window.setPixmap(item.source)
window.show()
window.activateWindow()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
提示:避免混合导入“样式”。您可以导入模块(
从PyQt5导入qtwidts,QtCore
)或相关类(从PyQt5.qtwidts导入(…)
)。要在图形视图中找到与项目对应的原始pixmap,您可以通过QGraphicsItem.setData()
将其作为数据存储在项目中
def central(self):
....
self.v_pixmap = self.u_pixmap.copy(rect)
self.pixmap = self.v_pixmap.scaled(200, 200, Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.item = QGraphicsPixmapItem()
self.item.setPixmap(self.pixmap)
self.item.setData(0, self.v_pixmap)
....
这将允许您通过item.data(0)
从项目中检索原始pixmap
要查找鼠标光标下的项目,可以使用main window.mousePressEvent
中的QGraphicsView.itemAt
。鼠标光标的位置由event.pos()
给出。但是,此位置相对于主窗口的局部坐标系。要将这些坐标与图形视图的坐标系匹配,需要将它们映射到图形视图和主窗口共用的坐标系,例如全局坐标系。考虑到这一点,MainWindow.mousePressEvent
将变成
def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
print("item clicked")
pos = self.mapToGlobal(event.pos())
pos1 = self.graphicsview.mapFromGlobal(pos)
item = self.graphicsview.itemAt(pos1)
if item:
u_pixmap = item.data(0)
if u_pixmap:
self.label.setPixmap(u_pixmap)
self.label.show()
要在图形视图中查找与项目对应的原始pixmap,可以通过
QGraphicsItem.setData()
将其作为数据存储在项目中,例如
def central(self):
....
self.v_pixmap = self.u_pixmap.copy(rect)
self.pixmap = self.v_pixmap.scaled(200, 200, Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.item = QGraphicsPixmapItem()
self.item.setPixmap(self.pixmap)
self.item.setData(0, self.v_pixmap)
....
这将允许您通过item.data(0)
从项目中检索原始pixmap
要查找鼠标光标下的项目,可以使用main window.mousePressEvent
中的QGraphicsView.itemAt
。鼠标光标的位置由event.pos()
给出。但是,此位置相对于主窗口的局部坐标系。要将这些坐标与图形视图的坐标系匹配,需要将它们映射到图形视图和主窗口共用的坐标系,例如全局坐标系。考虑到这一点,MainWindow.mousePressEvent
将变成
def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
print("item clicked")
pos = self.mapToGlobal(event.pos())
pos1 = self.graphicsview.mapFromGlobal(pos)
item = self.graphicsview.itemAt(pos1)
if item:
u_pixmap = item.data(0)
if u_pixmap:
self.label.setPixmap(u_pixmap)
self.label.show()
打开相应的原始图像是什么意思?@eyllanesc我想在另一个窗口中将原始(较大)图像显示为QPixmap-只是想知道如何让程序识别所选图像。打开相应的原始图像是什么意思?@eyllanesc我想显示原始(较大)图像把它想象成另一个窗口中的QPixmap——只是想知道如何让程序识别所选的图像。