在 MouseAdapter 和 Java swing 库中使用鼠标进行平移

问题描述 投票:0回答:1

我正在尝试在 Java 中实现 Convay 的生命游戏中实现缩放和平移功能。问题如下:

每次我们尝试通过拖动鼠标进行平移时,我们的视线都会出现在屏幕的左上角。这是负责实现此功能的类

package input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import renderer.Renderer;

public class PanningHandler extends MouseAdapter {
    private Renderer renderer;

    public PanningHandler(Renderer renderer) {
        this.renderer = renderer;
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // Check if the right mouse button is pressed (RMB)
        if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0) {
            handleRMBDrag(e);
        }
    }

    private void handleRMBDrag(MouseEvent e) {
        int deltaX = e.getX() - renderer.getLastMouseX();
        int deltaY = e.getY() - renderer.getLastMouseY();

        // Calculate new pan offset
        int newPanOffsetX = renderer.getPanOffsetX() - deltaX;
        int newPanOffsetY = renderer.getPanOffsetY() - deltaY;

        // Calculate maximum allowed values based on the size of the display area
        int maxPanOffsetX = getMaxPanOffsetX(); // Adjust this based on your requirements
        int maxPanOffsetY = getMaxPanOffsetY(); // Adjust this based on your requirements

        // Limit the pan offset to avoid going out of bounds
        newPanOffsetX = Math.max(0, Math.min(newPanOffsetX, maxPanOffsetX));
        newPanOffsetY = Math.max(0, Math.min(newPanOffsetY, maxPanOffsetY));

        // Set the new pan offset and repaint
        renderer.setPanOffsetX(newPanOffsetX);
        renderer.setPanOffsetY(newPanOffsetY);
        renderer.getFrame().repaint();

        // Update last mouse coordinates for the next iteration
        renderer.setLastMouseX(e.getX());
        renderer.setLastMouseY(e.getY());
    }

    // Rest of the code remains unchanged

    private int getMaxPanOffsetX() {
        return (int) (renderer.getWidth() * 10 * renderer.getZoomFactor() - renderer.getFrame().getWidth());
    }

    private int getMaxPanOffsetY() {
        return (int) (renderer.getHeight() * 10 * renderer.getZoomFactor() - renderer.getFrame().getHeight());
    }
}

这是渲染器中的一些位,负责绘制正方形和平移。

public class Renderer {
    private double zoomFactor = 1.0;
    private boolean gameState = false;
    private final Color BLACK = Color.BLACK;
    private final Color WHITE = Color.WHITE;
    private JFrame frame;
    private static Renderer instance;
    private int height = 100; // TODO - Handle the case when our grid becomes very large (e.g 1000x1000)
    private int width = 100;
    private boolean[][] grid = new boolean[height][width];
    private Logic logic = new Logic(); // instantiate Logic class
    private int lastMouseX = -1;
    private int lastMouseY = -1;
    private int panOffsetX = 0;
    private int panOffsetY = 0;

    private void configFrame() {
        frame.pack();
        frame.setSize(width * 10, height * 10);
        frame.getContentPane().setBackground(BLACK);

        // ...
        frame.addMouseMotionListener(new PanningHandler(this)); // TODO - make it work
        // ...

        frame.add(new MyPanel());
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    /**
     * Inner class representing the drawing panel inside the JFrame.
     */
    class MyPanel extends JPanel {
        public MyPanel() {
            setBackground(BLACK); // Set the background color to black
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            drawSquares(g);
        }
    }

    /**
     * Draws squares on the panel based on the current state of the grid.
     * 
     * @param g The Graphics object used for drawing.
     */
    public void drawSquares(Graphics g) {
        int squareSize = (int) (10 * zoomFactor);

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int x = (int) (j * squareSize - panOffsetX);
                int y = (int) (i * squareSize - panOffsetY);

                if (grid[i][j]) {
                    g.setColor(WHITE);
                    g.fillRect(x, y, squareSize, squareSize);
                } else {
                    g.setColor(BLACK);
                    g.fillRect(x, y, squareSize, squareSize);
                }
            }
        }
    }

    /**
     * Updates the grid based on the Game of Life rules.
     * Repaints the frame to reflect the changes.
     */
    public void updateGrid() {
        if (gameState) {
            grid = logic.gridUpdate(grid);
            frame.repaint();
        }
    }

    // ... (rest of the code)
}

我知道如果我们取消新的 PanOffsetX/Y 限制,

        // Limit the pan offset to avoid going out of bounds
        newPanOffsetX = Math.max(0, Math.min(newPanOffsetX, maxPanOffsetX));
        newPanOffsetY = Math.max(0, Math.min(newPanOffsetY, maxPanOffsetY));

然后它很快就会变成负数。每次当我们开始在任何位置拖动鼠标时 方向——我们让事情变得更糟。这可能就是它回到左上角的原因。

非常感谢有关此问题的任何帮助,干杯!

java swing conways-game-of-life
1个回答
0
投票

我设法修复了这个错误。通过更改我的 MyMouseListener。

旧版本代码

package input;

import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.SwingUtilities;

import renderer.Renderer;

/**
 * Custom MouseAdapter for handling mouse events in the Renderer.
 * This adapter is responsible for processing mouse clicks, releases, and drag events.
 */
public class MyMouseListener extends MouseAdapter {
    private final Renderer renderer;

    /**
     * Constructs a new MyMouseListener with the specified Renderer.
     *
     * @param renderer The Renderer associated with this adapter.
     */
    public MyMouseListener(Renderer renderer) {
        this.renderer = renderer;
    }

    /**
     * Invoked when the mouse is clicked.
     * Calls the handleMouseClick method to update the grid based on the mouse click.
     *
     * @param e The MouseEvent representing the mouse click event.
     */
    @Override
    public void mouseClicked(MouseEvent e) {
        // Check if the left mouse button is pressed (LMB). 
        // for some reason the never version BUTTON1_DOWN_MASK doesn't work, so I used the older version
        if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
            handleLMBClick(e);
        }
    }

    /**
     * Handles the mouse click event by updating the grid according to the click position.
     *
     * @param e The MouseEvent representing the mouse click event.
     */
    
    public void handleLMBClick(MouseEvent e) {
 
            int squareSize = (int) (10 * renderer.getZoomFactor());
        
            int x = (int) ((e.getX() + renderer.getPanOffsetX()) / squareSize);
            int y = (int) ((e.getY() + renderer.getPanOffsetY() - 40) / squareSize);
        
            // Clamp the indices to valid grid bounds
            x = Math.min(Math.max(0, x), renderer.getWidth() - 1);
            y = Math.min(Math.max(0, y), renderer.getHeight() - 1);
        
            renderer.reverseElement(y, x);
            System.out.println("Mouse Clicked: " + x + "," + y);
            renderer.getFrame().repaint(); // Repaint the frame to update the drawing
        
    }

    /**
     * Invoked when the mouse is released.
     * Resets the last mouse coordinates to -1, indicating no ongoing drag.
     *
     * @param e The MouseEvent representing the mouse release event.
     */
    // @Override
    // public void mouseReleased(MouseEvent e) {
    //     renderer.setLastMouseX(-1);
    //     renderer.setLastMouseY(-1);
    // }
}

新版本代码

package input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.SwingUtilities;

import renderer.Renderer;

/**
 * Custom MouseAdapter for handling mouse events in the Renderer.
 * This adapter is responsible for processing mouse clicks, releases, and drag
 * events.
 */
public class MyMouseListener extends MouseAdapter {
    private final Renderer renderer;

    /**
     * Constructs a new MyMouseListener with the specified Renderer.
     *
     * @param renderer The Renderer associated with this adapter.
     */
    public MyMouseListener(Renderer renderer) {
        this.renderer = renderer;
    }

    /**
     * Handles the mouse pressed event, updating the grid based on the click
     * position.
     * If the right mouse button is pressed, it records the initial mouse
     * coordinates for panning.
     * If the left mouse button is pressed, it calculates the grid indices and
     * toggles the cell state.
     * @param e The MouseEvent representing the mouse click event.
     */
    @Override
    public void mousePressed(MouseEvent e) {
        if (SwingUtilities.isRightMouseButton(e)) {
            renderer.setLastMouseX(e.getX());
            renderer.setLastMouseY(e.getY());
        } else {
            int squareSize = (int) (10 * renderer.getZoomFactor());

            int x = (int) ((e.getX() + renderer.getPanOffsetX()) / squareSize);
            int y = (int) ((e.getY() + renderer.getPanOffsetY() - 40) / squareSize);

            // Clamp the indices to valid grid bounds
            x = Math.min(Math.max(0, x), renderer.getWidth() - 1);
            y = Math.min(Math.max(0, y), renderer.getHeight() - 1);

            renderer.reverseElement(y, x);
            System.out.println("Mouse Clicked: " + x + "," + y);
            renderer.getFrame().repaint(); // Repaint the frame to update the drawing
        }
    }

}

© www.soinside.com 2019 - 2024. All rights reserved.