java - 在 JScrollPane 中调整 JPanel 大小时保持相对鼠标位置

标签 java swing resize

我正在调整 JScrollPane 内的 JPanel 的大小,我想确保 JPanel 上我的鼠标当前所在的点在调整大小后保持其相对于 JScrollPane 的位置(就像 Google map 在您放大/缩小)。

我在 JPanel 上找到了鼠标位置,这让我可以处理处于不同位置的视口(viewport)。我将它乘以缩放因子,这样我就知道缩放后该点的位置。然后我减去鼠标在 ScrollPane 上的位置,以便我知道该点相对于可视区域的位置。但是我做错了什么,我只是看不到什么。

示例代码:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;


public class Test 
{
    public static void main(String[] in)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Test();
            }
        });
    }

    public Test()
    {
        final JFrame frame = new JFrame();
        final ScalablePanel child = new ScalablePanel();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(child, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class ScalablePanel
extends JScrollPane
implements MouseWheelListener
{
    final double ZOOM_IN_FACTOR = 1.1;
    final double ZOOM_OUT_FACTOR = 0.9;
    final JPanel zoomPanel = new JPanel();

    public ScalablePanel()
    {
        final javax.swing.JLabel marker = new javax.swing.JLabel("Testing the mouse position on zoom");
        marker.setHorizontalAlignment(javax.swing.JLabel.CENTER);

        zoomPanel.setLayout(new BorderLayout());
        zoomPanel.add(marker,BorderLayout.CENTER);

        getViewport().setView(zoomPanel);
        setPreferredSize(new Dimension(300,300));
        addMouseWheelListener(this);
    }

    public void mouseWheelMoved(final MouseWheelEvent e) 
    {
        if (e.isControlDown())
        {
            if (e.getWheelRotation() < 0)
                zoomIn(e);
            else
                zoomOut(e);
            e.consume();
        }
    }

    public void zoomIn(final MouseWheelEvent e)
    {
        // Get the mouse position with respect to the zoomPanel
        final Point pointOnZoomPanel = SwingUtilities.convertPoint(
                e.getComponent(), e.getPoint(), zoomPanel);

        // Resize panel
        final Dimension currSize = zoomPanel.getSize();
        zoomPanel.setPreferredSize(
                new Dimension(
                        (int)(currSize.width * ZOOM_IN_FACTOR),
                        (int)(currSize.height * ZOOM_IN_FACTOR) ));

        // Find out where our point on the zoom panel is now that we've resized it
        final Point newViewPos = new Point();
        newViewPos.x = (int)(ZOOM_IN_FACTOR * pointOnZoomPanel.x - e.getPoint().x);
        newViewPos.y = (int)(ZOOM_IN_FACTOR * pointOnZoomPanel.y - e.getPoint().y);
        // Move the viewport to the new position to keep the area our mouse was in the same spot
        getViewport().setViewPosition(newViewPos);

        zoomPanel.revalidate();
    }

    public void zoomOut(final MouseWheelEvent e)
    {
        // Get the mouse position with respect to the zoomPanel
        final Point pointOnZoomPanel = SwingUtilities.convertPoint(
                e.getComponent(), e.getPoint(), zoomPanel);

        // Resize panel
        final Dimension currSize = zoomPanel.getSize();
        zoomPanel.setPreferredSize(
                new Dimension(
                        (int)(currSize.width * ZOOM_OUT_FACTOR),
                        (int)(currSize.height * ZOOM_OUT_FACTOR) ));

        // Find out where our point on the zoom panel is now that we've resized it
        final Point newViewPos = new Point();
        newViewPos.x = (int)(ZOOM_OUT_FACTOR * pointOnZoomPanel.x - e.getPoint().x);
        newViewPos.y = (int)(ZOOM_OUT_FACTOR * pointOnZoomPanel.y - e.getPoint().y);
        // Move the viewport to the new position to keep the area our mouse was in the same spot
        getViewport().setViewPosition(newViewPos);

        zoomPanel.revalidate();
    }
}

最佳答案

尝试找到鼠标位置占当前大小的百分比,然后将其应用到新大小:

newViewPos.x = (int)((ZOOM_IN_FACTOR * currSize.width) * (e.getPoint().x/(double)currSize.width));

举个例子。通过这种方式,您可以查看鼠标相对于滚动 Pane 的位置,并在 zoomPanel 上保留该关系。

关于java - 在 JScrollPane 中调整 JPanel 大小时保持相对鼠标位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/247071/

相关文章:

java - 如何从 JButton 检索数据?

java - 正则表达式匹配至少 2 个数字,字符串中任意顺序的 2 个字母

java - 如何在JTable中动态添加图片

Java:调整图像大小不起作用

c++ - 如何检查 std::vector 的调整大小是否有适当的内存

java - 调用方法时出现问题(扫雷)

java-8 流 : Are new streams from intermediate operations returned without increase in memory?

java - GridBagLayout 问题 : TextArea overlapping MenuBar

java - 如何让后代达到树中的某个级别?

c++ - qt | QPixmap 缩放不正确