java - JScrollPane "jumping"当滚动条开始使用时

标签 java swing viewport point

抱歉,下面是一段很长的示例代码,但问题是:

我有一个正在积极绘制的背景(我可能会很聪明,绘制一次并缩放它,但这也显示了问题)。

您可以使用鼠标滚轮放大和缩小图像。

这个想法是在鼠标指针下进行缩放的“谷歌地图”缩放。我注意到的是,直到图像足够大以使用两个滚动条时,它似乎才真正起作用。在那之前,您会得到图像变大,但锁定在原点。

“正确”的行为应该是移动 View 位置,即使滚动条尚未被超大图像使用。

我不确定如何解决这个问题(或者这是否正确且符合预期),而不在图像后面绘制更大的背景,使其不仅仅是填充视口(viewport)。

由于(我认为)同样的问题,它在一个或另一个滚动条接合后“跳跃”。

想法?

package com.hostigr.raw.io.client.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
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.JViewport;

public class TestFrame extends JFrame {

    public static void main(String[] arg) {
            new TestFrame();
    }

    public TestFrame() {
        initComponents();
        setVisible(true);
    }

    private void initComponents() {
        setLayout(new BorderLayout());

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 600);
        setPreferredSize(new Dimension(600, 600));

        add(new TopPanel());

    }

    private class TopPanel extends JPanel {
        JScrollPane scrollPane;

        public TopPanel() {
            setPreferredSize(new Dimension(500,500));
            scrollPane = new JScrollPane(new InteriorPanel());
            scrollPane.setPreferredSize(new Dimension(500,500));
            scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(10,490));
            scrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(490,10));
            scrollPane.setWheelScrollingEnabled(false);
            scrollPane.setHorizontalScrollBarPolicy(
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            scrollPane.setVerticalScrollBarPolicy(
                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            add(scrollPane);

        }
    }

    private class InteriorPanel extends JPanel {
        private double scale = 10.0;
        private final double scaleModifier = 0.1;
        private final int width = 10;
        private Point loc = new Point(0,0);
        private final int SIZE = 10;

        public InteriorPanel() {
            super(true);
            setPreferredSize(new Dimension((int)(scale * width * SIZE),
                    (int)(scale * width * SIZE)));
            this.addMouseWheelListener(new MapMouseWheelListener());
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2D = (Graphics2D) g;
            g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
            g2D.scale(scale,scale);

            for (int row = 0; row <= SIZE; row++) {
                for (int col = 0; col < SIZE; col++) {
                    if ((col + row) % 2 == 0) {
                        g2D.setColor(Color.white);
                    } else {
                        g2D.setColor(Color.black);
                    }
                    g2D.fillRect(col * width, row * width, width, width);
                }
            }

        }

        private void incrementScale(int notches) {
            double modifier = 0;
            double prevScale = scale;
            if (notches != 0) {
                modifier = 1.0 + -notches / Math.abs(notches) * scaleModifier;
            }
            scale = scale * Math.pow(modifier, Math.abs(notches));
            /*if (scale * width < 1) {
                scale = 1.0/width;
            } else if (scale * width * 3 > parentHeight || scale * width * 3 > parentWidth) {
                if (parentHeight > parentWidth) {
                    scale = parentWidth / 3.0 / width;
                } else {
                    scale = parentHeight / 3.0 / width;
                }
            } else if (scale * width * SIZE < parentWidth) {
                scale = parentWidth / (double)SIZE / width;
            } else if (scale * width * SIZE < parentHeight) {
                scale = parentHeight / (double)SIZE / width;
            }*/

            this.repaint();
            setPreferredSize(new Dimension((int)(scale * width * SIZE),
                    (int)(scale * width * SIZE)));

            JViewport viewport = ((JViewport)(getParent().getParent().getComponent(0)));
            Point orig = viewport.getViewPosition();
            viewport.setViewPosition(new Point(
                    orig.x - (int)Math.round(loc.x*(1 - scale/prevScale)),
                    orig.y - (int)Math.round(loc.y*(1 - scale/prevScale))));
            System.out.println(orig + "\n  " + loc + "\n  " + (1 - scale / prevScale));
            revalidate();
        }

        private class MapMouseWheelListener implements MouseWheelListener {

            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                loc = e.getPoint();
                incrementScale(e.getWheelRotation());
            }
        }
    }
}

最佳答案

看起来像 JViewPort#scrollRectToVisible(Rectangle r) 对我来说有效

     viewport.scrollRectToVisible(new Rectangle(new Point(
     orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
     orig.y - (int) Math.round(loc.y * (1 - scale / prevScale)))));

编辑并使用正确的 Swing 重绘规则,那么您的 codeBlock 必须以 revalidate() 结尾; + 重绘();

        setPreferredSize(new Dimension((int) (scale * width * SIZE), 
        (int) (scale * width * SIZE)));
        JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0)));
        Point orig = viewport.getViewPosition();
        /*viewport.setViewPosition(new Point(
                orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
                orig.y - (int) Math.round(loc.y * (1 - scale / prevScale))));*/
        viewport.scrollRectToVisible(new Rectangle(new Point(
                orig.x - (int) Math.round(loc.x * (1 - scale / prevScale)),
                orig.y - (int) Math.round(loc.y * (1 - scale / prevScale)))));
        System.out.println(orig + "\n  " + loc + "\n  " + (1 - scale / prevScale));

        revalidate();
        repaint();

关于java - JScrollPane "jumping"当滚动条开始使用时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6819243/

相关文章:

用于 Web 应用程序的 Java 图形库?

java - 验证 HTML 单元格中的数据并根据时间间隔显示消息

java - 如何尝试使用 jtextfield 捕获异常?

java - 如何将按钮 Action 监听器绑定(bind)到文本字段

java - 多个按钮的ActionListener-Swing

java - 当我尝试在 net-beans 中运行它时,我收到 "java.lang.reflect.InvocationTargetException"。为什么会发生这种情况?

java - 反转 Java For 循环

java - 调整大小后剪切 OpenGL/GLSL 视口(viewport)

jquery - 加载/调整大小时的视口(viewport)查找类删除 jQuery

jquery - zepto.js : Viewport and Lazyload plugins?