如何在 JScrollPane 内实现位置敏感缩放?
我正在尝试在 JScrollPane
内实现位置敏感缩放。 JScrollPane
包含一个具有自定义 paint
的组件,该组件将在分配的任何空间内绘制自己 - 因此缩放就像使用 MouseWheelListener
一样简单根据需要调整内部组件的大小。
但我也希望放大(或缩小)一个点,以使该点在生成的放大(或缩小)视图中尽可能居中(这就是我所说的“位置敏感”缩放),类似谷歌地图中缩放的工作原理。 我确信这之前已经做过很多次了——有人知道在 Java Swing 下执行此操作的“正确”方法吗? 使用 Graphic2D
的转换而不是使用 JScrollPanes
会更好吗?
示例代码如下:
package test;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class FPanel extends javax.swing.JPanel {
private Dimension preferredSize = new Dimension(400, 400);
private Rectangle2D[] rects = new Rectangle2D[50];
public static void main(String[] args) {
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(400, 400);
jf.add(new JScrollPane(new FPanel()));
jf.setVisible(true);
}
public FPanel() {
// generate rectangles with pseudo-random coords
for (int i=0; i<rects.length; i++) {
rects[i] = new Rectangle2D.Double(
Math.random()*.8, Math.random()*.8,
Math.random()*.2, Math.random()*.2);
}
// mouse listener to detect scrollwheel events
addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int n, Point p) {
double d = (double) n * 1.08;
d = (n > 0) ? 1 / d : -d;
int w = (int) (getWidth() * d);
int h = (int) (getHeight() * d);
preferredSize.setSize(w, h);
getParent().doLayout();
// Question: how do I keep 'p' centered in the resulting view?
}
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.red);
int w = getWidth();
int h = getHeight();
for (Rectangle2D rect : rects) {
r.setRect(rect.getX() * w, rect.getY() * h,
rect.getWidth() * w, rect.getHeight() * h);
((Graphics2D)g).draw(r);
}
}
}
I am trying to implement position-sensitive zooming inside a JScrollPane
. The JScrollPane
contains a component with a customized paint
that will draw itself inside whatever space it is allocated - so zooming is as easy as using a MouseWheelListener
that resizes the inner component as required.
But I also want zooming into (or out of) a point to keep that point as central as possible within the resulting zoomed-in (or -out) view (this is what I refer to as 'position-sensitive' zooming), similar to how zooming works in google maps. I am sure this has been done many times before - does anybody know the "right" way to do it under Java Swing?. Would it be better to play with Graphic2D
's transformations instead of using JScrollPanes
?
Sample code follows:
package test;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class FPanel extends javax.swing.JPanel {
private Dimension preferredSize = new Dimension(400, 400);
private Rectangle2D[] rects = new Rectangle2D[50];
public static void main(String[] args) {
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(400, 400);
jf.add(new JScrollPane(new FPanel()));
jf.setVisible(true);
}
public FPanel() {
// generate rectangles with pseudo-random coords
for (int i=0; i<rects.length; i++) {
rects[i] = new Rectangle2D.Double(
Math.random()*.8, Math.random()*.8,
Math.random()*.2, Math.random()*.2);
}
// mouse listener to detect scrollwheel events
addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int n, Point p) {
double d = (double) n * 1.08;
d = (n > 0) ? 1 / d : -d;
int w = (int) (getWidth() * d);
int h = (int) (getHeight() * d);
preferredSize.setSize(w, h);
getParent().doLayout();
// Question: how do I keep 'p' centered in the resulting view?
}
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.red);
int w = getWidth();
int h = getHeight();
for (Rectangle2D rect : rects) {
r.setRect(rect.getX() * w, rect.getY() * h,
rect.getWidth() * w, rect.getHeight() * h);
((Graphics2D)g).draw(r);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
测试了一下,似乎有效...
更新
这里有一个解释:点
p
是鼠标相对于FPanel
的位置。 由于您正在缩放面板的大小,因此p
的位置(相对于面板的大小)将按相同的系数缩放。 通过从缩放位置减去当前位置,您可以得到调整面板大小时点“移动”的量。 然后只需将滚动窗格中的面板位置向相反方向移动相同的量即可将p
放回鼠标光标下方。Tested this, seems to work...
Update
Here is an explanation: the point
p
is the location of the mouse relative to theFPanel
. Since you are scaling the size of the panel, the location ofp
(relative to the size of the panel) will scale by the same factor. By subtracting the current location from the scaled location, you get how much the point 'shifts' when the panel is resized. Then it is simply a matter of shifting the panel location in the scroll pane by the same amount in the opposite direction to putp
back under the mouse cursor.这是@Kevin K 解决方案的一个小重构:
Here's a minor refactoring of @Kevin K's solution:
您的 MouseWheelListener 还必须找到光标,将其移动到 JScrollPane 的中心,并调整要查看的内容的 xmin/ymin 和 xmax/ymax。
Your MouseWheelListener also has to locate the cursor, move it to the center of the JScrollPane and adjust the xmin/ymin and xmax/ymax of the content to be viewed.
我认为像这样的 smt 应该有效...
编辑:
改变了几件事。
I think smt like this should be working...
EDIT:
Changed a couple things.