0

我正在构建一个 GUI,用于使用QGraphicsSceneQGraphicsPixmapItem(下面的代码)在网格中显示照片(来自文件夹)。现在我想在单击其中一个时打开相应的原始图像QGraphicsPixmapItems。如果我在内部单击,我会覆盖 MousePressEvent 并使程序执行“某些操作” QGraphicsScene,但是现在我想知道如何检索单击了哪个项目的信息以打开相应的图像。

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

2 回答 2

1

首先,在使用循环时,连续设置相同的实例属性是完全没用的:每次循环循环时self.u_pixmapself.pixmap都会self.item被覆盖。

然后,总是从当前聚焦的对象(或小部件)中捕获鼠标事件;因为您的mousePressEvent覆盖是针对 QMainWindow 实例,而当前的焦点对象是 QGraphicsView,所以您永远不会得到任何鼠标事件,因为图形视图会捕获它。

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

作为旁注, usingself.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, 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 (...))。

于 2020-11-04T13:49:00.580 回答
1

要在图形视图中找到对应于项目的原始像素图,您可以通过 将其作为数据存储在项目中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).

要查找鼠标光标下的项目,您可以使用QGraphicsView.itemAtin 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()
于 2020-11-04T14:56:37.463 回答