JScrollPane «прыгает», когда начинают использоваться полосы прокрутки - PullRequest
1 голос
/ 25 июля 2011

Извините, это длинный пример кода ниже, но вот проблема:

У меня есть фон, который я активно рисую (я мог бы быть умным и нарисовать его один раз и просто масштабировать его, но это также показывает проблему).

Вы можете использовать колесо мыши для увеличения и уменьшения изображения.

Идея состоит в том, чтобы сделать масштабирование "карты Google", гдемасштабируется под указателем мыши.Что я заметил, так это то, что он, похоже, не будет себя вести, пока изображение не станет достаточно большим, чтобы использовать обе полосы прокрутки.До этого вы получаете изображение, которое становится больше, но привязано к источнику.

«Правильное» поведение должно заключаться в том, что позиция обзора перемещается, даже если полосы прокрутки еще не используются увеличенным изображением.

Я не уверен, как обойти это(или если это правильно и ожидаемо) без рисования намного большего фона позади изображения, чтобы он больше, чем заполняет область просмотра.

Он «прыгает» после того, как одна или другая полоса прокрутки включается из-за (я думаю)тот же вопрос.

Мысли?

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 Ответ

1 голос
/ 25 июля 2011

выглядит как 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();
...