简体   繁体   中英

Draw a ball in a Panel and move the ball using mouseDragged

I am practicing to draw a ball in the Panel and show the ball's coordinate when the ball is dragged.

This is my first time to practice a drawing exercise(?)

This is my code.

import java.awt.*;
 import java.awt.event.*;

public class MovingBall extends Frame {
Panel ballPanel = new Panel();
Label ballLabel = new Label();
Panel coordinatePanel = new Panel();
Label coordinateLabel = new Label();
int x0=0,y0 =0, x=20,y=30;
int nowX, nowY;
Label nowXcoordinateLabel = new Label("Now X :"+nowX);
Label nowYcoordinateLabel = new Label("Now Y :"+nowY);
MovingBall(){
    setLayout(new GridLayout(1,1));
    ballPanel.add(ballLabel); coordinatePanel.add(coordinateLabel);

    add(ballPanel);
    add(coordinatePanel);
    ballPanel.setBackground(Color.white);

    coordinatePanel.setBackground(Color.LIGHT_GRAY);
    nowXcoordinateLabel.setBackground(Color.WHITE);
    nowYcoordinateLabel.setBackground(Color.WHITE);
    coordinatePanel.add(nowXcoordinateLabel);
    coordinatePanel.add(nowYcoordinateLabel);
    setVisible(true);
    setSize(400,400);

    MouseMotionListener ml = new MouseMotionAdapter(){
   public void mouseDragged(MouseEvent e){
      Point p = new Point();
      nowX = (int) p.getX();
      nowY = (int) p.getY();
  }  
};
    addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent we) {
        dispose();
     }
    }
   );
  }
   public void paintComponent(Graphics2D gg){
   // super.paintComponents(gg);
    ballPanel.paintComponents(gg);
    gg.setColor(Color.BLUE);
    gg.fillOval(x0, y0, 10, 10);

}



public static void main(String[]arg){
    MovingBall mb = new MovingBall();
}
}

I have two problems

  1. I used fillOval and paintComponent to draw and display a ball but I don't see that on the screen. Why?
  2. Any idea how to move the ball if I want to move that using mouseDragged ? Do I need some thread?

Let's start with

  • Frame doesn't have a paintComponent method, so nothing is ever going to call it.
  • Even if it did, position 0x0 would paint the circle under the frame's borders, so you wouldn't see it
  • You should be getting the Point from the MouseEvent , not from the new Point object you've created
  • It's not the responsibility of the frame to manage the mouse dragged or painting, the frame is responsible for providing the initial container onto which everything else added

From that, you should move the functionality of the painting and mouse dragged management to it's own class. This provides you with two things, first, a surface onto which you can paint, and which will contained within the frame borders and the mouse events will automatically be converted to the panels context ( 0x0 will be the top left corner of the panel)

This raises the question about how to update the labels. Well, you could take a leaf from the AWT API and use a simple observer pattern to generate events when the coordinates are changed, for example

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

public class MovingBall extends Frame {

    BallPane ballPanel = new BallPane();
    Label ballLabel = new Label();
    int x0 = 0, y0 = 0, x = 20, y = 30;
    int nowX, nowY;
    Label nowXcoordinateLabel = new Label("Now X :" + nowX);
    Label nowYcoordinateLabel = new Label("Now Y :" + nowY);

    MovingBall() {
        setLayout(new BorderLayout());
        ballPanel.add(ballLabel);

        add(ballPanel);
        ballPanel.setBackground(Color.white);

        nowXcoordinateLabel.setBackground(Color.WHITE);
        nowYcoordinateLabel.setBackground(Color.WHITE);
        setVisible(true);
        setSize(400, 400);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                dispose();
            }
        });

        Panel coordinates = new Panel(new FlowLayout());
        coordinates.add(nowXcoordinateLabel);
        coordinates.add(nowYcoordinateLabel);
        coordinates.setBackground(Color.LIGHT_GRAY);
        add(coordinates, BorderLayout.SOUTH);

        ballPanel.addCoordinateListene(new CoordinateListener() {
            @Override
            public void coordinatesChanged(CoordinateEvent evt) {
                nowXcoordinateLabel.setText("Now X: " + evt.getCoordinate().getX());
                nowYcoordinateLabel.setText("Now X: " + evt.getCoordinate().getY());
                revalidate();
                repaint();
            }
        });

    }

    public static void main(String[] arg) {
        MovingBall mb = new MovingBall();
    }

    public class CoordinateEvent extends EventObject {
        private final Point p;

        public CoordinateEvent(Object source, Point p) {
            super(source);
            this.p = p;
        }

        public Point getCoordinate() {
            return p;
        }
    }

    public interface CoordinateListener {
        public void coordinatesChanged(CoordinateEvent evt);
    }

    public class BallPane extends Panel {

        int x0 = 0, y0 = 0, x = 20, y = 30;
        private List<CoordinateListener> coordinateListeners;

        public BallPane() {
            MouseMotionListener ml = new MouseMotionAdapter() {
                public void mouseDragged(MouseEvent e) {
                    x0 = (int) e.getX();
                    y0 = (int) e.getY();
                    fireCoordinateChange(new Point(e.getPoint()));
                    repaint();
                }
            };
            addMouseMotionListener(ml);
            coordinateListeners = new ArrayList<>(5);
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            g.setColor(Color.BLUE);
            g.fillOval(x0, y0, 10, 10);
        }

        public void addCoordinateListene(CoordinateListener listener) {
            coordinateListeners.add(listener);
        }

        public void removeCoordinateListene(CoordinateListener listener) {
            coordinateListeners.remove(listener);
        }

        protected void fireCoordinateChange(Point p) {
            CoordinateEvent evt = new CoordinateEvent(this, p);
            for (CoordinateListener listener : coordinateListeners) {
                listener.coordinatesChanged(evt);
            }
        }

    }
}

Make your class extending Panel and make it ready to drawing with overriding paint method and add the MouseMotionListener to listining your panel.Get X and Y coordinates for using in paint method, at last add your drawing panel to Frame .

Simple code : UPDATED

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TestClass extends Panel {


        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        Panel ballPanel = new Panel();
        Label ballLabel = new Label();
        Panel coordinatePanel = new Panel();
        Label coordinateLabel = new Label();
        int nowX, nowY;
        Label nowXcoordinateLabel = new Label("Now X :");
        Label nowYcoordinateLabel = new Label("Now Y :");

        TestClass() {

            coordinatePanel.add(coordinateLabel);
            nowXcoordinateLabel.setBackground(Color.WHITE);
            nowYcoordinateLabel.setBackground(Color.WHITE);
            nowXcoordinateLabel.setPreferredSize(new Dimension(100, 25));
            nowYcoordinateLabel.setPreferredSize(new Dimension(100, 25));
            coordinatePanel.setPreferredSize(new Dimension(400, 30));
            coordinatePanel.setBackground(Color.LIGHT_GRAY);
            coordinatePanel.add(nowXcoordinateLabel);
            coordinatePanel.add(nowYcoordinateLabel);

            MouseAdapter ml = new MouseAdapter() {

                @Override
                public void mouseMoved(MouseEvent e) {
                    nowXcoordinateLabel.setText("Now X :" + e.getX());
                    nowYcoordinateLabel.setText("Now Y :" + e.getY());
                    nowX = e.getX();
                    nowY = e.getY();
                    repaint();
                    super.mouseMoved(e);
                }

            };


            setLayout(new GridLayout(1, 1));
            setBackground(Color.WHITE);
            addMouseMotionListener(ml);
            setVisible(true);
            setSize(400, 400);
        }


        @Override
        public void paint(Graphics g) {
            Graphics2D gg = (Graphics2D) g;
            gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            gg.setColor(Color.BLUE);
            gg.fillOval(nowX, nowY, 20, 20);

        }

        public static void main(String[] arg) {
            TestClass mb = new TestClass();
            Frame frame = new Frame("Test drawing");
            frame.addWindowListener(new WindowAdapter() {


                @Override
                public void windowClosing(WindowEvent e) {
                     frame.dispose();
                    super.windowClosing(e);
                }


            });
            frame.setLayout(new GridLayout(1, 1));
            frame.add(mb);
            frame.add(mb.coordinatePanel);
            frame.setSize(800, 600);
            frame.setVisible(true);
        }


}

To get the position of the mouse instead of:

nowX = (int) p.getX();

Write this:

nowX = (int) e.getX();

You also need to redraw the oval every time the user triggers a Mouse Drag event

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM