スクロールバーの使用開始時にJScrollPaneが「ジャンプ」する

java point swing viewport
スクロールバーの使用開始時にJScrollPaneが「ジャンプ」する

申し訳ありませんが、これは以下の長いサンプルコードですが、問題は次のとおりです。

私は積極的に描いている背景があります(おそらく賢くて一度描いて、それをスケーリングするだけかもしれませんが、これも問題を示しています)。

マウスホイールを使用して、画像をズームインおよびズームアウトできます。

アイデアは、マウスポインタの下でズームする「グーグルマップ」ズームを行うことです。 私が気づいたのは、画像が両方のスクロールバーを使用するのに十分な大きさになるまで実際には動作しないように見えることです。 それまでは、画像は単純に大きくなりますが、原点に固定されます。

「正しい」動作は、スクロールバーがまだ特大の画像で使用されていない場合でも、ビューポジションが移動することです。

ビューポートを塗りつぶすよりも大きな背景を画像の後ろに描画せずに、これを回避する方法がわかりません(またはこれが正しいと予想される場合)。

同じ問題のために、スクロールバーが1つまたは他のバーと連動した後に「ジャンプ」します。

考えですか?

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

  1  0


ベストアンサー

私にとっては「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()で終了する必要があります。 + 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))));*/
        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();

1


タイトルとURLをコピーしました