Java - MouseListener Action Event in paintComponent

前端 未结 2 644
隐瞒了意图╮
隐瞒了意图╮ 2021-01-22 19:46

Here i have a code which draws a rectangle on the mouseClicked position using the paintComponent.I can get the output message but anything related to graphics and .draw() wont w

相关标签:
2条回答
  • 2021-01-22 20:17

    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):

    enter image description here

    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;
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-22 20:24

    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.

    0 讨论(0)
提交回复
热议问题