- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一个简单的图像查看器并实现平移和缩放功能(分别使用鼠标拖动和鼠标滚轮滚动)。我已经成功地实现了平移(简单模式)和天真的“进入左上角”缩放。
我现在想细化缩放,使缩放时用户鼠标的坐标成为“焦点”:也就是说,缩放时,平移会更新,以便用户鼠标下的(图像的)像素保持不变相同(以便他们真正放大那个区域)
图像是通过在一个普通的 QWidget 上覆盖 paintEvent 来查看的。
尽我所能尝试使用直观的方法,我似乎无法实现正确的缩放行为。
属性 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
完全用于平移,指的是 初始鼠标按下的位置 和 此时的 ImageView 位置时间(分别))
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()
我想要上述效果,但 anchor 在滚动时位于用户的鼠标上。这是我的尝试,效果非常轻微:缩放仍然不是我想要的,而是滚动到鼠标的一般区域,没有锚定。事实上,将鼠标保持在同一位置并放大似乎遵循一条弯曲的路径,向右平移然后向左平移。
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
感谢任何帮助!
最佳答案
好的,我设法让它工作
def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
screenpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = screenpoint.x(), screenpoint.y()
oldpoint = (screenpoint.x() + self.position[0], screenpoint.y() + self.position[1])
newpoint = (oldpoint[0] * (self.scale/oldscale),
oldpoint[1] * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)
这里的逻辑:
问题确实是图像和显示坐标之间的细微混淆。
关于python - 放大图像时控制平移(锚定点),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20942586/
大家好,我完成了这个基本的 C 程序,它向输入任何给定数字集的用户显示有序集、最小值、最大值、平均值和中值。我遇到的问题是,当我打印数字时,我必须使用诸如“3.2%f”之类的东西来设置标准的精度,我怎
我有这个基于 Python 的服务守护进程,它正在执行大量多路复用 IO(选择)。 从另一个脚本(也是 Python)我想查询这个服务守护进程的状态/信息和/或控制处理(例如暂停它、关闭它、更改一些参
我读到 Fortran 对表达式求值的顺序有严格的规则。对于某些数值算法来说,这一点非常重要。 数值 C 程序如何控制浮点运算的顺序并防止编译器“优化”到不需要的运算顺序,例如将 (a*b)*c 更改
上下文: 整个问题可以概括为我正在尝试复制调用system(或fork)的行为,但在 mpi 环境中。 (事实证明,你不能并行调用system。)这意味着我有一个程序在许多节点上运行,每个节点上有一个
我考虑过控制scanf来接受c中的任何输入。我的概念是等待10秒(或任何其他时间)来接受任何输入。10秒后它将退出并且不再接收任何输入。 int main(){ int a,b,c,d; sca
我正在尝试使用生成器停止 setTimeOut 上的执行流程。我究竟做错了什么?我无法让 console.log 每 1500 毫秒退出一次。我是 node 的新手,如果我在做一件非常愚蠢的事情,请不
我希望我的应用程序的 Activity 堆栈包含同一 Activity 的多个实例,每个实例处理不同的数据。因此,我将让 Activity A 在我的 Activity 堆栈中处理数据 a、b、c 和
我有这个 bash 文件,它向设备询问 OpenSSH 的 IP、密码等。 现在,如果我使用 ssh root@ip,我必须输入密码。这真的很烦人。第二;我不能让我的脚本向它发送命令。 这就是我想要的
我正在尝试测试我有权访问的机器的缓存属性。为此,我正在尝试读取内存并对其计时。我改变工作集大小和步幅访问模式以获得不同的测量值。 代码如下所示: clock1 = get_ticks() for (i
我正在尝试编写一个 makefile 来替换用于构建相当大的应用程序的脚本之一。 当前脚本一次编译一个文件,使用 make 的主要原因是并行化构建过程。使用 make -j 16 我目前在办公室服务器
我正在制作一个小的测试程序,它演示了一个粗糙的控制台界面。 该程序是一个低于标准的典型获取行、响应程序,它甚至不识别“退出”,并希望您通过按 control-c 强制退出。在 Mingw32 上完成。
好的,我有一个 VOIP 电话。我知道电话的 IP 地址和端口,并且可以完全访问电话,我正在使用它通过 SIP 中继调用 SIP 电话。 我基本上想随时查看手机上发生的事情,但我不知道从哪里开始。 如
是否可以指定 CWinApp::WriteProfileString() 使用的应用程序名称? 如果我使用 CWinApp::SetRegistryKey 将我的公司名称设置为“MyCompany”,
我正在尝试用 Python 控制 Tor。我在 stackoverflow 上阅读了其他几个关于这个主题的问题,但没有一个能回答这个问题。 我正在寻找一种方法,以便在命令运行时为您提供“新身份”、新
最近在做一个项目,涉及到iPhone设备和手表传输数据、控制彼此界面跳转,在网上找了很多资料,发现国内的网站这方面介绍的不多,而国外的网站写的也不是很全,所以在这写这篇文章,给大家参考一下,望大神指
我想增加图中值的范围。在示例中,值的范围从 50 到 200。但是,我需要按如下方式分配值:50 75 100 125 150 175 200 并且最好使用 scale_fill_gradientn
我有一个IconButton,当按下时波纹效果是圆形的并且比按钮的面积大,我怎样才能减少点击按钮时波纹效果的大小? IconButton( constraints
我正在使用代码契约(Contract)为我的项目生成附属程序集。基本上它为项目的 MyAssembly.dll 创建一个 MyAssembly.Contracts.dll。这应该放在你的程序集旁边,但
我想使用分面绘制图形,其中面板之间的边缘不同。面板按字母顺序自动排序(按照 ggplot 中的惯例)。一个简单的例子: library(igraph) library(ggraph) g <- mak
我想为我的 Android 应用程序创建一个小部件,以显示有关位置的一些实时详细信息,例如天气。但我想在任何时候允许最多 3 个小部件实例,每个实例都有不同的位置。我不确定该怎么做,也找不到任何信息。
我是一名优秀的程序员,十分优秀!