Java - MouseListener Action Event in paintComponent

江枫思渺然 提交于 2019-12-01 23:53:20

Some suggestions on current code:

  • Watch class naming scheme i.e testclass should be TestClass or even better Test (but thats nit picking). All class names begin with capital letter and each new word thereafter is capitalized.

  • Dont extend JFrame unnecessarily.

  • Dont call setBounds on JFrame rather use appropriate LayoutManager and/or override getPreferredSize() of JPanel and return dimensions which fits its content.

  • Always call pack() on JFrame before setting it visible (taking above into consideration).

  • Use MouseAdapter vs MouseListener

  • Dont call moveBall() in paintComponent rather call it in your Timer which repaints the screen, not only slightly better design but we also should not do possibly long running tasks in paint methods.

As for your problem I think your logic is a bit skewed.

One approach would see the Rectangle (or Rectangle2D) get replaced by its own custom class (which will allow us to store attributes like color etc). Your ball would also have its own class which has the method moveBall() and its attributes like x and y position etc. On every repaint() your JPanel would call the method to move the ball, the JPanel itself could wrap the moveBall() in its own public method which we could than call from the timer which repaints the screen.

Here is an example of your code with above fixes implemented (please analyze it and if you have any questions let me know):

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.*;

public class Test {

    private MyPanel p;
    private Timer t;

    public Test() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initComponents();
        frame.add(p);

        frame.pack();
        frame.setVisible(true);

        t.start();
    }

    private void initComponents() {
        final ActionListener action = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                p.moveEntities();//moves ball etc
                p.repaint();
            }
        };

        t = new Timer(50, action);
        p = new MyPanel();

        p.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN);
                System.out.println("clicked");
            }
        });

        p.setBackground(Color.WHITE);
    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }
}

class MyPanel extends JPanel {

    int width = 300, height = 300;
    ArrayList<MyRectangle> entities = new ArrayList<>();
    MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height);

    void addEntity(int x, int y, int w, int h, Color c) {
        entities.add(new MyRectangle(x, y, w, h, c));
    }

    void moveEntities() {
        ball.moveBALL();
    }

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

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.setColor(ball.getColor());
        g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height);

        for (MyRectangle entity : entities) {
            g2d.setColor(entity.getColor());
            g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height);
        }
    }

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

class MyRectangle extends Rectangle2D.Double {

    Color color;

    public MyRectangle(double x, double y, double w, double h, Color c) {
        super(x, y, w, h);
        color = c;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return color;
    }
}

class MyBall extends Ellipse2D.Double {

    int xspeed = 1;
    int yspeed = 1;
    Color color;
    private final int maxWidth;
    private final int maxHeight;

    public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) {
        super(x, y, w, h);
        color = c;
        this.width = w;//set width and height of Rectangle2D
        this.height = h;
        //set max width and height ball can move
        this.maxWidth = maxWidth;
        this.maxHeight = maxHeight;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    void moveBALL() {
        x = x + xspeed;
        y = y + yspeed;
        if (x < 0) {
            x = 0;
            xspeed = -xspeed;
        } else if (x > maxWidth - ((int) getWidth() / 2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed
            x = maxWidth - ((int) getWidth() / 2);
            xspeed = -xspeed;
        }
        if (y < 0) {
            y = 0;
            yspeed = -yspeed;
        } else if (y > maxHeight - ((int) getHeight() / 2)) {
            y = maxHeight - ((int) getHeight() / 2);
            yspeed = -yspeed;
        }
    }
}

First of all the paint component is called every time swing needs to redraw the component.
And you are adding a new instance of mouse listener to the panel every time the paint is called.

Just move the line
p.addMouseListener(new MouseListener() {...}
out of the paint component, preferably after the initialization of the panel.

default template is

JPanel p = new JPanel(){
    @Override
    public void paintComponent(Graphics g) {
    }
};
p.addMouseListener(new MouseListener()  or new MouseAdapter()
//Your overridden methods

});

Hope this helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!