python - 如何使用 wheelEvent 将调整大小的 QGraphicPixmap 放置到 QGraphicsScene 中,同时保持光标下的相同像素
问题描述
我想使用wheelEvent
来调整图像大小并将 aQGraphicPixmap
放入QGraphicsScene
.
在添加原始图像之前,将其大小调整为原始大小的 1/3 左右。在 wheelEvent 中,我正在调用一个函数,该函数将调整原始图像的大小并创建一个QImage
来设置QGraphicsPixmap
.
将调整大小的像素图添加到场景后,缩放前光标下的像素发生了偏移。我不确定我需要映射到场景/从场景映射到哪些位置才能实现这一点。
我尝试过缩放 graphicsPixmap、缩放和转换 graphicsPixmap、缩放视图和转换 graphicsPixmap/设置偏移量。
我显然不知道发生了什么,但我不确定那是什么..
下面的 WheelEvent 可以完美运行,直到maybe_resize
被调用。
根据查看器中当前图像的大小,该maybe_resize
方法将调整当前 ndarray 图像的大小,创建一个新的 qimage 并在 graphicsPixmap 中设置一个新的像素图,或者退出该方法而不调整大小。
如果按原样运行代码,则像素图位于光标下的同一位置,但如果取消注释,maybe_resize
则不再是这种情况。
from PyQt5.QtCore import QRectF, QSize, Qt, pyqtSignal
import cv2
import numpy as np
from PyQt5.QtCore import QRectF, QSize, Qt, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import (QApplication,
QFrame,
QGraphicsPixmapItem,
QGraphicsScene,
QGraphicsView,
QMainWindow,
QSizePolicy)
class GraphicsView(QGraphicsView):
def __init__(self, parent):
super(GraphicsView, self).__init__(parent)
self.pixmap = QPixmap()
self._zoom_level = 0
self._scene = Scene(self)
self.setScene(self._scene)
self.gpm = QGraphicsPixmapItem()
self._scene.addItem(self.gpm)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.has_image = False
def maybe_resize(self, factor):
self.resize_requested(factor)
def read_image(self, path):
self.base_image = cv2.imread(path, -1)
self._original_res = self.base_image.shape
h, w = self.base_image.shape[0], self.base_image.shape[1]
self.resized_image = cv2.resize(self.base_image, (w // 4, h // 4))
self.has_image = True
self.set_image(self.resized_image)
return self.resized_image
def resize_requested(self, factor):
factor = max(1. * (self._zoom_level * factor), 1)
h = int(self.resized_image.shape[0] * factor)
w = int(self.resized_image.shape[1] * factor)
src = cv2.resize(self.base_image, (w, h))
dst = np.ndarray(src.shape, src.dtype)
dst[:, :, :] = src
self.set_image(dst)
def wheelEvent(self, event):
factor = 1.1
if event.angleDelta().y() < 0:
factor = 0.9
self._zoom_level-=1
else:
self._zoom_level+=1
view_pos = event.pos()
scene_pos = self.mapToScene(view_pos)
self.centerOn(scene_pos)
self.scale(factor, factor)
delta = self.mapToScene(view_pos) - self.mapToScene(self.viewport().rect().center())
self.centerOn(scene_pos - delta)
# self.maybe_resize(factor)
def set_image(self, img):
if not self.has_image:
return
shape = img.shape
w = shape[1]
h = shape[0]
self._image = img
q_img_format = QImage.Format_RGB888
try:
bands = shape[2]
except IndexError:
bands = 1
q_img = QImage(img, w, h, w * bands, q_img_format)
self.pixmap = self.pixmap.fromImage(q_img)
self.setSceneRect(QRectF(self.pixmap.rect()))
self.gpm.setPixmap(self.pixmap)
class Scene(QGraphicsScene):
zoom_changed = pyqtSignal(float)
def __init__(self, parent=None):
super(Scene, self).__init__(parent)
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.gv = GraphicsView(self)
self.setCentralWidget(self.gv)
def load_image(self, path):
self.gv.read_image(path)
def sizeHint(self):
return QSize(800, 800)
if __name__ == "__main__":
app = QApplication([])
w = Window()
w.load_image('test.jpg')
w.show()
app.exit(app.exec_())
解决方案
推荐阅读
- vba - 如何提高大型数据库循环的运行时间?
- javascript - 类型'可观察的
' 不可分配给类型 'Observable ' TS2322 - node.js - 预期的换行符为“LF”,但发现为“CRLF”(Entando 框架)
- terraform - terraform 块有什么用?
- android-studio - 从java转换为kotlin时如何修复转换错误
- office365 - 有没有办法让带有链接到PowerPoint文件的按钮在Office Online上打开?
- html - 从网站 URL 中删除文件夹名称的正确方法
- php - 通过php在mysql中使用空值更新日期时间
- python - conda环境应该是python3.5,但是使用python 2.7
- xamarin.android - Xamarin Android:如何在上下文操作模式下更改项目的位置