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——只是想知道如何让程序识别所选的图像。