【问题标题】:Draw a ball in a Panel and move the ball using mouseDragged在 Panel 中绘制一个球并使用 mouseDragged 移动球
【发布时间】:2017-10-28 13:04:13
【问题描述】:

我正在练习在Panel中画一个球,并在拖动球时显示球的坐标。

这是我第一次练习绘画练习(?)

这是我的代码。

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();
}
}

我有两个问题

  1. 我使用fillOvalpaintComponent 绘制并显示了一个球,但我在屏幕上看不到它。为什么?
  2. 如果我想使用mouseDragged 移动球,知道如何移动球吗?我需要一些线程吗?

【问题讨论】:

  • 您将此标记为 Swing 问题,因此您应该使用 Swing 组件,而不是 AWT 组件。 Swing 组件以"J" (JButton, JPanel...) 开头;阅读 Swing 教程中关于 [自定义绘画]() 的部分,了解绘画的基础知识。工作代码显示了如何在鼠标事件上更改正方形的位置。修改你处理 mouseDragged 的​​代码。
  • AWT Frame 没有paintComponent 方法,将@Override 添加到方法中,会产生编译器错误。这也不是您应该如何进行自定义绘画,ballPanel 应该进行绘画,而不是框架。人们在 10 多年前就停止使用 AWT,使用 Swing 或 Java FX 会得到更好的响应
  • 我知道我的 mouseDragged 是错误的,但我这样做只是为了检查我的 Label 是否正常工作。
  • @MadProgrammer 谢谢你的好建议!但是我必须学习awt,因为我下周要进行java测试。 . :(
  • @MadProgrammer 你是什么意思“ballPanel 应该在做paintitng,而不是框架。”?你能再解释一下吗?

标签: java graphics awt java-2d


【解决方案1】:

开始吧

  • Frame 没有 paintComponent 方法,所以永远不会调用它。
  • 即使是这样,位置 0x0 也会在框架边框下绘制圆圈,因此您不会看到它
  • 您应该从MouseEvent 中获取Point,而不是从您创建的新Point 对象中获取
  • 框架不负责管理鼠标拖动或绘画,框架负责提供初始容器,其他所有内容都添加到该容器中

从此,您应该将绘画和鼠标拖动管理的功能移至它自己的类。这为您提供了两件事,首先,您可以在其上绘制的表面,它将包含在框架边框内,并且鼠标事件将自动转换为面板上下文(0x0 将是面板的左上角)

这就提出了如何更新标签的问题。好吧,您可以从 AWT API 中获取一个叶子,并使用一个简单的观察者模式来在坐标更改时生成事件,例如

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);
            }
        }

    }
}

【讨论】:

    【解决方案2】:

    使您的类扩展Panel 并准备好使用覆盖paint 方法进行绘图并将MouseMotionListener 添加到列出您的面板。获取X 和Y 坐标以在paint 方法中使用,最后添加您的绘图面板到Frame

    简单代码:已更新

    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);
            }
    
    
    }
    

    【讨论】:

    • 虽然我肯定会推荐 Swing over AWT,但 OP 至少有两次声明 '我必须学习 awt,因为下周我将进行 java 测试" - 你'还破坏了油漆链,这可能会产生不需要的油漆伪影
    【解决方案3】:

    获取鼠标的位置,而不是:

    nowX = (int) p.getX();
    

    这样写:

    nowX = (int) e.getX();
    

    你还需要在每次用户触发鼠标拖动事件时重新绘制椭圆

    【讨论】:

    • 是的,我知道我这样做是为了检查我的标签是否正常工作。但我已经尝试过你的建议 (0,0,-10,-10) 但这不起作用
    • (0,0,-10,-10) - Graphics 不支持负宽度/高度,使用 Frame 时将对象定位在0x0,因为画布会将对象放置在框架边框下,但是总而言之,这不是最初的问题
    • @ProgramLover 尝试在填充前添加颜色 gg.setColor(Color.orange);
    • @MaurizioRicci 是
    猜你喜欢
    • 2016-08-05
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    相关资源
    最近更新 更多