单击相应的QGraphicsPixmapItem时如何打开图像?

问题描述

我正在构建一个GUI,用于使用QGraphicsSceneQGraphicsPixmapItem(下面的代码)在网格中显示照片(来自文件夹)。现在,我想在单击QGraphicsPixmapItems之一时打开相​​应的原始图像。如果我在QGraphicsScene内单击,我将覆盖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,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_pixmapself.pixmapself.item将被覆盖。 / p>

然后,总是从当前聚焦的 object (或 widget )捕获鼠标事件;由于您的mousePressEvent替代对象是QMainWindow实例,而当前的焦点对象是QGraphicsView,您将永远不会获取任何鼠标事件,因为图形视图将捕获它。

最后,为了实现所需的功能,您需要为图形项实现mousePressEvent,但是由于QGraphicsItem不是 一个QObject子类,因此无法直接创建新的信号,如果不使用自定义的“信号代理”,则为信号。

作为旁注,使用self.resize()也完全没有用,因为您使用的是self.showMaximized()

这是您要实现的目标的可能实现:

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,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_())

提示:避免混合导入“样式”。您可以导入模块(from PyQt5 import QtWidgets,QtCore)或相关类(from PyQt5.QtWidgets import (...))。

,

要在图形视图中找到与某个项目相对应的原始像素图,您可以通过QGraphicsItem.setData()将其作为数据存储在该项目中,例如

def central(self):
    ....
    self.v_pixmap = self.u_pixmap.copy(rect)
    self.pixmap = self.v_pixmap.scaled(200,Qt.SmoothTransformation)

    self.item = QGraphicsPixmapItem()
    self.item.setPixmap(self.pixmap)
    self.item.setData(0,self.v_pixmap)

    ....

这将允许您通过item.data(0)从项目中检索原始像素图。

要在鼠标光标下找到项目,可以在QGraphicsView.itemAt中使用MainWindow.mousePressEvent。鼠标光标的位置由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()

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...