我正在编写一个简单的图像浏览器,并实现了平移和缩放功能(分别使用鼠标拖动和鼠标滚轮滚动)。我已成功实现了平移(简易模式)和朴素的 '缩放到左上角'。
我现在想要完善缩放功能,使用户在缩放时所在位置成为“焦点”,也就是说,在缩放时更新平移,使得用户鼠标下的像素保持不变(以便他们真正地将焦点放在那个区域进行缩放)。
该图像通过重写 paintEvent 在其他普通 QWidget 上进行查看。
尽管我采取了直观的方法,但似乎无法实现正确的缩放行为。
一个属性
以下是实际的图像显示方式。
这里是平移代码(相对简单):
(
这里是缩放代码带有平移功能,以保留可见区域左上角的(锚点)。当您进行缩放时,屏幕左上角的像素不会改变。
我希望实现上述效果,但需要将 固定点 与用户的鼠标滚动一起移动。这是我的尝试,虽然效果不完美:缩放仍未达到预期,但会滚动到鼠标的一般区域,而没有进行固定。实际上,在相同位置保持鼠标并进行缩放似乎会沿着曲线路径向右平移然后向左平移。
这个理论的基础是,在缩放之前,鼠标下方的像素距离左上角(位置)的长度为dx和dy。缩放后,我们计算该像素的新位置,并通过调整
我不确定我哪里做错了:我怀疑
我想象这对于文件查看器来说是一个很常见的任务(因为大多数似乎都这样缩放),但我发现很难研究算法。
这里是完整的代码(需要PyQt4)来调整缩放:
http://pastebin.com/vvpdZy9g 感谢您的帮助!
我现在想要完善缩放功能,使用户在缩放时所在位置成为“焦点”,也就是说,在缩放时更新平移,使得用户鼠标下的像素保持不变(以便他们真正地将焦点放在那个区域进行缩放)。
该图像通过重写 paintEvent 在其他普通 QWidget 上进行查看。
尽管我采取了直观的方法,但似乎无法实现正确的缩放行为。
一个属性
scale
表示当前的缩放级别(缩放比例为2意味着图像的显示大小是其真实大小的两倍,0.5 意味着一半,而 scale > 0),而 position
是当前查看的图像区域的左上角坐标(通过平移实现)。以下是实际的图像显示方式。
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.drawImage(0, 0,
self.image.scaled(
self.image.width() * self.scale,
self.image.height() * self.scale,
QtCore.Qt.KeepAspectRatio),
self.position[0], self.position[1])
painter.end()
这里是平移代码(相对简单):
(
pressed
和anchor
完全用于平移,分别指代初始鼠标按下的位置和当时图像视图的位置)def mousePressEvent(self, event):
self.pressed = event.pos()
self.anchor = self.position
def mouseReleaseEvent(self, event):
self.pressed = None
def mouseMoveEvent(self, event):
if (self.pressed):
dx, dy = event.x() - self.pressed.x(), event.y() - self.pressed.y()
self.position = (self.anchor[0] - dx, self.anchor[1] - dy)
self.repaint()
这里是缩放代码不尝试调整平移。它导致所有东西从/到屏幕左上角缩小或增大。
def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
self.repaint()
这里是缩放代码带有平移功能,以保留可见区域左上角的(锚点)。当您进行缩放时,屏幕左上角的像素不会改变。
def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200
if (self.scale < 0.1):
self.scale = oldscale
self.position = (self.position[0] * (self.scale / oldscale),
self.position[1] * (self.scale / oldscale))
self.repaint()
我希望实现上述效果,但需要将 固定点 与用户的鼠标滚动一起移动。这是我的尝试,虽然效果不完美:缩放仍未达到预期,但会滚动到鼠标的一般区域,而没有进行固定。实际上,在相同位置保持鼠标并进行缩放似乎会沿着曲线路径向右平移然后向左平移。
def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
oldpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = oldpoint.x() - self.position[0], oldpoint.y() - self.position[1]
newpoint = (oldpoint.x() * (self.scale/oldscale),
oldpoint.y() * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)
这个理论的基础是,在缩放之前,鼠标下方的像素距离左上角(位置)的长度为dx和dy。缩放后,我们计算该像素的新位置,并通过调整
self.position
使其位于屏幕上的相同坐标下,即在像素的西侧和北侧的dx和dy处。我不确定我哪里做错了:我怀疑
old point
映射到我的屏幕坐标时出了问题,或者更可能的是:我的数学有误,因为我混淆了像素和屏幕坐标。
我尝试了一些直观的变化,但没有接近预期的锚定点。我想象这对于文件查看器来说是一个很常见的任务(因为大多数似乎都这样缩放),但我发现很难研究算法。
这里是完整的代码(需要PyQt4)来调整缩放:
http://pastebin.com/vvpdZy9g 感谢您的帮助!