Как мне манипулировать фигурами в увеличенной панели в Java?

#java #swing #scroll #graphics #mouseover

#java #swing #прокрутка #графика #наведение курсора мыши

Вопрос:

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

Есть несколько вещей, которые я хотел бы сделать с этими фигурами, но для начала, как я могу покрасить два прямоугольника объекта в красный цвет, когда мышь перемещается внутри них?

Вот код, который у меня есть на данный момент:

 import java.awt.BasicStroke;
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.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

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

public class CanvasPane extends JPanel {

    private static Canvas canvas;

    public CanvasPane(boolean isDoubleBuffered) {
        super(isDoubleBuffered);
        setLayout(new BorderLayout());
        canvas = new Canvas(1.0);
        JScrollPane pane = new JScrollPane(canvas);
        pane.getViewport().setBackground(Color.DARK_GRAY);
        add(pane, BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Test Graphics");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(new CanvasPane(true), BorderLayout.CENTER);
        frame.pack();
  
        frame.setSize(800, 600);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        //Initial scrolling of the canvas to its center
        Rectangle canvasRectangle = canvas.getBounds();
        Rectangle visibleRectangle = canvas.getVisibleRect();
        double tx = (canvasRectangle.getWidth() - visibleRectangle.getWidth())/2;
        double ty = (canvasRectangle.getHeight() - visibleRectangle.getHeight())/2;
        visibleRectangle.setBounds((int)tx, (int)ty, visibleRectangle.width, visibleRectangle.height);
        canvas.scrollRectToVisible(visibleRectangle);
    }
}

class Canvas extends JComponent implements MouseWheelListener, MouseMotionListener, MouseListener {

    private static final long serialVersionUID = 1L;
    private double zoom = 1.0;
    public static final double SCALE_STEP = 0.1d;
    private Dimension initialSize;
    private Point origin;
    private double previousZoom = zoom;
    private double scrollX = 0d;
    private double scrollY = 0d;
    private Rectangle2D workspace = new Rectangle2D.Double(0,0, 1024, 768);
    
    private Rectangle entity1 = new Rectangle(10, 10, 100, 100);
    private Rectangle entity2 = new Rectangle(300, 300, 100, 100);

    public Canvas(double zoom) {
        this.zoom = zoom;
        addMouseWheelListener(this);
        addMouseMotionListener(this);
        addMouseListener(this);
        setAutoscrolls(true);
        setPreferredSize(new Dimension((int)workspace.getWidth(), (int)workspace.getHeight()));
    }

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

        //Zoom graphics
        g2d.scale(zoom, zoom);

        //translate graphics to be always in center of the canvas
        Rectangle size = getBounds();
        double tx = ((size.getWidth() - workspace.getWidth() * zoom) / 2) / zoom;
        double ty = ((size.getHeight() - workspace.getHeight() * zoom) / 2) / zoom;
        g2d.translate(tx, ty);

        //Draw
        g2d.setColor(Color.LIGHT_GRAY);
        g2d.fill(workspace);
                       
        g2d.setColor(Color.DARK_GRAY);
        g2d.setStroke(new BasicStroke(5.0f));
        g2d.draw(workspace);
        
        g2d.draw(entity1);
        g2d.draw(entity2);        
    }

    @Override public void setSize(Dimension size) {
        super.setSize(size);
        if (initialSize == null) {
            this.initialSize = size;
        }
    }

    @Override public void setPreferredSize(Dimension preferredSize) {
        super.setPreferredSize(preferredSize);
        if (initialSize == null) {
            this.initialSize = preferredSize;
        }
    }

    public void mouseWheelMoved(MouseWheelEvent e) {
        double zoomFactor = -SCALE_STEP * e.getPreciseWheelRotation() * zoom;
        zoom = Math.abs(zoom   zoomFactor);
        
        //Here we calculate new size of canvas relative to zoom.
        Dimension d = new Dimension(
                (int)(initialSize.width * zoom),
                (int)(initialSize.height * zoom));
            setPreferredSize(d);
            setSize(d);
            validate();
        followMouseOrCenter(e.getPoint());
        previousZoom = zoom;
    }

    public void followMouseOrCenter(Point2D point) {
        Rectangle size = getBounds();
        Rectangle visibleRect = getVisibleRect();
        scrollX = size.getCenterX();
        scrollY = size.getCenterY();
        
        if (point != null) {
            scrollX = point.getX() / previousZoom * zoom - (point.getX() - visibleRect.getX());
            scrollY = point.getY() / previousZoom * zoom - (point.getY() - visibleRect.getY());
        }

        visibleRect.setRect(scrollX, scrollY, visibleRect.getWidth(), visibleRect.getHeight());
        scrollRectToVisible(visibleRect);
    }

    public void mouseDragged(MouseEvent e) {
        if (origin != null) {
            int deltaX = origin.x - e.getX();
            int deltaY = origin.y - e.getY();
            Rectangle view = getVisibleRect();
            view.x  = deltaX;
            view.y  = deltaY;
            scrollRectToVisible(view);
        }
    }

    public void mousePressed(MouseEvent e) {
        origin = new Point(e.getPoint());
    }
       
    public void mouseMoved(MouseEvent e) {


    }
    
    public void mouseClicked(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
}
  

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

 public void mouseMoved(MouseEvent e) {

    double x = e.getX() / zoom;
    double y = e.getY() / zoom;

    double x2 = getWidth() - workspace.getWidth() * zoom; 
    double y2 = getHeight() - workspace.getHeight() * zoom; 
    
    if(x2 > 0) x -= x2;
    if(y2 > 0) y -= y2;
    
    Point p = new Point((int)x, (int)y);
    
    if(entity1.contains(p)) {
        intersects = true;
    } 
    else {
        intersects = false;
    }       
    repaint();
}
  

Комментарии:

1. но для начала, как я могу покрасить два прямоугольника объекта в красный цвет, когда мышь перемещается внутри них? — сначала вам нужно немного реструктурировать свой код. 1) вам нужно сохранить ArrayList объектов, которые вы хотите нарисовать. 2) Объекту в ArrayList потребуется информация о форме, которую вы хотите нарисовать, и цвете, который вы хотите нарисовать. Тогда ваш метод paintComponent() просто выполнит итерацию по списку массивов и раскрасит каждый объект. Смотрите DrawOnComponent пример из пользовательских подходов к рисованию .

2. Тот, который изменен. затем вы сможете использовать ArrayList, чтобы определить, когда мышь переместилась на фигуру. Сначала вам нужно будет настроить точку мыши на коэффициент масштабирования, затем вы должны выполнить итерацию по списку массивов, чтобы найти фигуру, содержащую точку мыши. Затем вы меняете цвет и перерисовываете.

3. Это работает, если я не выполняю масштабирование… но как только я увеличиваю масштаб, он больше не работает… Я пытался использовать значение масштабирования, но это тоже не сработало…. Я предполагаю, что мне нужно выполнить этот перевод методом MouseMove, но я не уверен в вычислении

4. Я не могу поверить, что вы внесли все эти предложенные изменения за 6 минут. Какую отладку вы выполнили за эти 6 минут? Может быть, вам нужно «разделить» на коэффициент масштабирования? Посмотрите на значения, которые вы вычисляете, и посмотрите, имеют ли они смысл?

5. Я ввожу оператор печати «CLICK» следующим образом: public void mouseMoved(MouseEvent e) { if(entity1.contains(e.getPoint())) { System.out.println («ЩЕЛЧОК»); } else { System.out.println(«ПРОМАХ»); } } я попробую разделить ….

Ответ №1:

Кажется, это работает еще лучше, но я не уверен, что это самое чистое решение…

 public void mouseMoved(MouseEvent e) {

    double x = e.getX() / zoom;
    double y = e.getY() / zoom;

//  double x2 = getWidth() - workspace.getWidth() * zoom; 
//  double y2 = getHeight() - workspace.getHeight() * zoom; 
        
    double x2 = ((getWidth() - workspace.getWidth() * zoom) / 2) / zoom;
    double y2 = ((getHeight() - workspace.getHeight() * zoom) / 2) / zoom;

    
    
    if(x2 > 0) x -= x2;
    if(y2 > 0) y -= y2;
    
    Point p = new Point((int)x, (int)y);
    
    if(entity1.contains(p)) {
        intersects = true;
    } 
    else {
        intersects = false;
    }       
    repaint();
}