问题描述
我正在构建一个GUI,用于使用QGraphicsScene
和QGraphicsPixmapItem
(下面的代码)在网格中显示照片(来自文件夹)。现在,我想在单击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_pixmap
,self.pixmap
和self.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()