Java: изменение размера компонента без перерисовки? - PullRequest
1 голос
/ 16 января 2012

Я работаю над Java-программой, которая отображает карту (унаследованную от JComponent) в пределах JScrollPane. Когда срабатывает MouseWheelListener, карта увеличивается, и область просмотра JScrollPane корректируется так, чтобы центрироваться на месте мыши.

Это все работает нормально, за исключением того, что вызов setSize(Dimension d) заставляет карту перерисовываться непосредственно перед настройкой вида, вызывая "заикание". Тем не менее, я не могу настроить представление до тех пор, пока setSize не завершит выполнение или вычисления для «центрирования» области просмотра не станут бесполезными (из-за вызовов getHeight() и getWidth()), поэтому настройка области просмотра находится в пределах runnable, вызываемого с помощью invokeLater.

Я хотел бы найти способ перейти непосредственно от предыдущего размера карты и местоположения области просмотра к новому виду, не видя сцену, перекрашенную дважды.

setIgnoreRepaint(boolean) не работает для меня. Есть ли другой способ сделать это?

РЕДАКТИРОВАТЬ: Вот то, что я разработал из вашего примера кода, который повторяет мою проблему, хотя и не так заметно, как на чертеже происходит гораздо меньше вычислений. Если вы быстро прокрутите изображение, вы увидите, что между изменением размера шестиугольников до их нового размера и настройкой области просмотра в новое положение есть небольшое заикание.

Вы можете видеть, что шестиугольники перерисовываются дважды. (Один раз, когда вызывается метод setSize (), и один раз, когда вызывается метод setViewPosition ().)

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class ZoomWithSelectionInViewport implements MouseWheelListener{

private int zoom = 80;

JComponent b;
int hexSize = 3;

public ZoomWithSelectionInViewport() throws Exception{

    b = new JComponent() {

        private static final long serialVersionUID = 1L;

        @Override
        public Dimension getMinimumSize() {
            return new Dimension(700, 700);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = ((Graphics2D) g);

            int vertOffsetX, vertOffsetY, horizOffsetX, horizOffsetY;

            vertOffsetX = (int)((double)hexSize* Math.sqrt(3.0f));
            vertOffsetY = (int)((double)-hexSize-1* Math.sqrt(3.0f)/2.0f);

            horizOffsetX = (int) ((double)hexSize* Math.sqrt(3.0f));
            horizOffsetY = (int) ((double)hexSize+1* Math.sqrt(3.0f)/2.0f);

            for(int x = 0; x < 50; x++)
            {
                for(int y = 0; y < 50; y++)
                {
                    int[] xcoords = new int[6]; int[] ycoords = new int[6];
                     for(int i = 0; i < 6; i++)
                     {
                        xcoords[i] = (int)((hexSize+x * horizOffsetX + y * vertOffsetX) + (double)hexSize * Math.cos(i * 2 * Math.PI / 6));
                        ycoords[i] = (int)(((getSize().height /2 )+ x * horizOffsetY + y * vertOffsetY) + (double)hexSize * Math.sin(i * 2 * Math.PI / 6));
                     }
                     g2d.setStroke(new BasicStroke(hexSize/2.5f));
                     g2d.setColor(Color.GRAY);

                     g2d.drawPolygon(xcoords, ycoords, 6);
                }
            }

        }
    };
    JScrollPane view = new JScrollPane(b);

    b.addMouseWheelListener(this);
    JFrame f = new JFrame();
    f.setLocation(10, 10);
    f.setDefaultCloseOperation(3);
    f.add(view);
    f.setSize(500,500);
    f.setVisible(true);
    view.setWheelScrollingEnabled(false);
}

    public void mouseWheelMoved(MouseWheelEvent e) {
        zoom = 100*-Integer.signum(e.getWheelRotation());
        if(hexSize - Integer.signum(e.getWheelRotation()) > 0)
            hexSize-= Integer.signum(e.getWheelRotation());
        Dimension targetSize = new Dimension(b.getWidth()+zoom,b.getHeight()+zoom);
        b.setPreferredSize(targetSize);
        b.setSize(targetSize);

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JViewport tempView = (JViewport)b.getParent();
                tempView.setViewPosition(new Point(b.getWidth()/2,b.getHeight()/2));            
            }
        });

    }


public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            try {
                ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}
}

1 Ответ

4 голосов
/ 16 января 2012

мое любопытство, не знаю, что произойдет, не могли бы вы использовать это SSCCE добавьте туда свои проблемы и отредактируйте с помощью кода свой вопрос

enter image description here enter image description hereenter image description hereenter image description here

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class ZoomWithSelectionInViewport {

    private Point startPoint = new Point(0, 0);
    private Point rectLocale = new Point();
    private Dimension rectSize = new Dimension();
    private int zoom = 80;
    private BufferedImage capture = null;
    private BufferedImage raw;

    public ZoomWithSelectionInViewport() throws Exception {
        raw = new Robot().createScreenCapture(new Rectangle(
                Toolkit.getDefaultToolkit().getScreenSize()));
        MouseBehavior behavior = new MouseBehavior();
        JPanel b = new JPanel() {

            private static final long serialVersionUID = 1L;

            @Override
            public Dimension getMinimumSize() {
                return new Dimension(500, 500);
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(500, 500);
            }

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = ((Graphics2D) g);
                g2d.drawImage(raw, 0, 0, null);
                if (capture != null) {
                    int width2 = (int) (rectSize.width + rectSize.width * (zoom / 500d));
                    int height2 = (int) (rectSize.height + rectSize.height * (zoom / 500d));
                    int x2 = rectLocale.x - ((width2 - rectSize.width) / 2);
                    int y2 = rectLocale.y - ((height2 - rectSize.height) / 2);
                    Image scaledInstance = capture.getScaledInstance(
                            width2, height2, Image.SCALE_AREA_AVERAGING);
                    g2d.drawImage(scaledInstance, x2, y2, null);
                    g2d.drawRect(x2, y2, width2, height2);
                } else {
                    g2d.draw(new Rectangle(rectLocale, rectSize));
                }
            }
        };
        b.addMouseMotionListener(behavior);
        b.addMouseListener(behavior);
        b.addMouseWheelListener(behavior);
        JFrame f = new JFrame();
        f.setLocation(10, 10);
        f.setDefaultCloseOperation(3);
        f.add(b);
        f.pack();
        f.setVisible(true);
    }

    private class MouseBehavior extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            startPoint = e.getPoint();
            rectLocale = new Point();
            rectSize = new Dimension();
            capture = null;
            if (e.getSource() instanceof JComponent) {
                ((JComponent) e.getSource()).repaint();
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            Point currentPoint = e.getPoint();
            rectSize.width = Math.abs(currentPoint.x - startPoint.x);
            rectSize.height = Math.abs(currentPoint.y - startPoint.y);
            if (e.isShiftDown()) {
                rectSize.width = rectSize.height = Math.min(rectSize.width, rectSize.height);
                int dx = startPoint.x - rectSize.width;
                int dy = startPoint.y - rectSize.height;
                rectLocale.x = startPoint.x < currentPoint.x ? startPoint.x : Math.max(dx, dy);
                rectLocale.y = startPoint.y < currentPoint.y ? startPoint.y : Math.min(dx, dy);
            } else {
                rectLocale.x = Math.min(currentPoint.x, startPoint.x);
                rectLocale.y = Math.min(currentPoint.y, startPoint.y);
            }
            if (e.getSource() instanceof JComponent) {
                ((JComponent) e.getSource()).repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (rectSize.width <= 0 || rectSize.height <= 0) {
                capture = null;
            } else {
                capture = raw.getSubimage(Math.max(0, rectLocale.x),
                        Math.max(0, rectLocale.y), rectSize.width, rectSize.height);
            }
            if (e.getSource() instanceof JComponent) {
                ((JComponent) e.getSource()).repaint();
            }
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            zoom = Math.min(2000, Math.max(0, zoom + e.getUnitsToScroll() * 10));
            if (e.getSource() instanceof JComponent) {
                ((JComponent) e.getSource()).repaint();
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

альтернативой может быть

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;

public class ZoomDemo {

    private PaintSurface canvas = new PaintSurface();
    private JFrame frame = new JFrame();
    private AffineTransform aT = new AffineTransform();
    private Point2D p1 = null;
    private Point2D p2 = null;

    public ZoomDemo() {
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        ScaleListener scaleListener = new ScaleListener();
        canvas.addMouseWheelListener(scaleListener);
        canvas.addMouseListener(scaleListener);    
        frame.add(canvas);
        frame.setVisible(true);
    }

    public class ScaleListener extends MouseAdapter {

        private double scale = 1;

        @Override
        public void mouseClicked(MouseEvent e) {
            p1 = e.getPoint();
            try {
                p2 = aT.inverseTransform(p1, new Point2D.Double());
                /*
                 * p1 is the point relative to canvas where the user physically
                 * held the mouse.
                 *
                 * Since you may want to deal with a virtual mouse location
                 * relative to an untransformed canvas, you inverse transform p1
                 * to p2.
                 *
                 * For example: when the user held the mouse over, let's say,
                 * the displayed left upper corner of the red rectangle.
                 *
                 * p2 now will point to the upper left corner of the red
                 * rectangle in an untransformed canvas.
                 */
                applyScale();
            } catch (NoninvertibleTransformException e1) {
                e1.printStackTrace();
            }
            canvas.repaint();
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            if (p1 != null && p2 != null) {
                scale -= (0.05 * e.getWheelRotation());
                if (scale > 5) {
                    scale = 5;
                }
                if (scale < 1) {
                    scale = 1;
                    aT.setToIdentity();
                } else {
                    applyScale();
                }
                canvas.repaint();
            }
        }

        private void applyScale() {
            aT.setToIdentity();
            // *** variation one (your implementation)
            aT.translate(p1.getX(), p1.getY());
            aT.scale(scale, scale);
            aT.translate(-p2.getX(), -p2.getY());
            // *** variation two
            // aT.translate(p1.getX(), p1.getY());
            // aT.scale(scale, scale);
            // aT.translate(-p1.getX(), -p1.getY());
            // *** variation three
            // aT.translate(p2.getX(), p2.getY());
            // aT.scale(scale, scale);
            // aT.translate(-p2.getX(), -p2.getY());
        }
    }

    public class PaintSurface extends JComponent {

        private static final long serialVersionUID = 1L;

        {
            this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        }

        /*
         * Override paintComponent, not paint!!!
         */
        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g.create();
            try {
                g2.setColor(Color.black);
                g2.fillRect(0, 0, getWidth(), getHeight());
                // g2.setTransform(aT); <<<<<<<<< !!!!!!!
        /*
                 * A transform (translation for example) may already have been
                 * applied to the Graphics object by a parent. This is removed
                 * by setTransform.
                 */
                g2.transform(aT); // <<<<<<<<<< !!!!!!!
                g2.setColor(Color.red);
                g2.drawRect(50, 50, 100, 100);
                g2.setColor(Color.blue);
                g2.drawRect(200, 200, 150, 50);
                if (p2 != null) {
                    g2.setColor(Color.green);
                    g2.fill(new Rectangle2D.Double(p2.getX() - 4, p2.getY() - 4, 8, 8));
                }
            } finally {
                g2.dispose();
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ZoomDemo zoomDemo = new ZoomDemo();
            }
        });
    }
}

тот же вопрос,

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.Rectangle;
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;

///4922670/jscrollpane-prygaet-kogda-nachinayt-ispolzovatsya-polosy-prokrutki

public class LockViewPortToPoint extends JFrame {

    private static final long serialVersionUID = 1L;

    public static void main(String[] arg) {
        LockViewPortToPoint lockViewPortToPoint = new LockViewPortToPoint();
    }

    public LockViewPortToPoint() {
        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 {

        private static final long serialVersionUID = 1L;
        private JScrollPane scrollPane;

        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 static final long serialVersionUID = 1L;
        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;
        private Point orig = new Point(250, 250);

        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;
            final double prevScale = scale;
            if (notches != 0) {
                modifier = 1.0 + -notches / Math.abs(notches) * scaleModifier;
            }
            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;
            }*/
            setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE)));
            orig = new Point(((int) (scale * width * SIZE)) / 2, ((int) (scale * width * SIZE) / 2));
            final JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0)));
            javax.swing.SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    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();
        }

        private class MapMouseWheelListener implements MouseWheelListener {

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

другой пример

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;

///107994/kak-vy-realizuete-pozitsionnoe-masshtabirovanie-vnutri-jscrollpane
public class FPanel extends javax.swing.JPanel {

    private static final long serialVersionUID = 1L;
    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() {

            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                updatePreferredSize(e.getWheelRotation(), e.getPoint());
            }
        });
    }

    private void updatePreferredSize(int wheelRotation, Point stablePoint) {
        double scaleFactor = findScaleFactor(wheelRotation);
        scaleBy(scaleFactor);
        Point offset = findOffset(stablePoint, scaleFactor);
        offsetBy(offset);
        getParent().doLayout();
        revalidate();
        repaint();
    }

    private double findScaleFactor(int wheelRotation) {
        double d = wheelRotation * 1.08;
        return (d > 0) ? 1 / d : -d;
    }

    private void scaleBy(double scaleFactor) {
        int w = (int) (getWidth() * scaleFactor);
        int h = (int) (getHeight() * scaleFactor);
        preferredSize.setSize(w, h);
    }

    private Point findOffset(Point stablePoint, double scaleFactor) {
        int x = (int) (stablePoint.x * scaleFactor) - stablePoint.x;
        int y = (int) (stablePoint.y * scaleFactor) - stablePoint.y;
        return new Point(x, y);
    }

    private void offsetBy(Point offset) {
        Point location = getLocation();
        setLocation(location.x - offset.x, location.y - offset.y);
    }

    @Override
    public Dimension getPreferredSize() {
        return preferredSize;
    }
    private Rectangle2D r = new Rectangle2D.Float();

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...