如何在JScrollPane中实现位置敏感的缩放

如何在JScrollPane中实现位置敏感的缩放

本文介绍了如何在JScrollPane中实现位置敏感的缩放?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 JScrollPane 中实现位置敏感的缩放。 JScrollPane 包含一个具有自定义 paint 的组件,它将在分配的任何空间内绘制自己 - 因此缩放就像使用 MouseWheelListener 可以根据需要调整内部组件的大小。

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.

但我也希望放大(或者输出) )在得到的放大(或 - )视图中将该点保持为中心的点(这就是我所说的'位置敏感'缩放),类似于缩放在谷歌地图中的工作方式。我确信之前已经做了很多次 - 有没有人知道在Java Swing下做权利的方式?使用 Graphic2D 的转换而不是使用 JScrollPanes

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?

示例代码如下:

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);
    }
  }
}


推荐答案

经过测试,似乎有效......

Tested this, seems to work...

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);

    int offX = (int)(p.x * d) - p.x;
    int offY = (int)(p.y * d) - p.y;
    setLocation(getLocation().x-offX,getLocation().y-offY);

    getParent().doLayout();
}

更新

以下是解释:点 p 是鼠标相对于 FPanel 。由于您要缩放面板的大小, p 的位置(相对于面板的大小)将按相同的因子缩放。通过从缩放位置减去当前位置,可以获得调整面板大小时点移动的程度。然后,只需将滚动窗格中的面板位置向相反方向移动相同的量,即将 p 放回鼠标光标下。

Here is an explanation: the point p is the location of the mouse relative to the FPanel. Since you are scaling the size of the panel, the location of p (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 put p back under the mouse cursor.

这篇关于如何在JScrollPane中实现位置敏感的缩放?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 09:50