Java - PaintComponent 中的 MouseListener 操作事件

标签 java swing events draw paintcomponent

这里我有一个代码,它使用paintComponent在鼠标单击的位置上绘制一个矩形。我可以获得输出消息,但与图形和.draw()相关的任何内容都不起作用。

代码:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public final class testclass extends JFrame {

    static JPanel p;
    Timer t;
    int x = 1;
    int y = 1;
    int xspeed = 1;
    int yspeed = 1;

    public testclass() {
        initComponents();
        this.setBounds(100, 300, 500, 500);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        t.start();
        this.add(p);
    }

    public void initComponents() {
        final ActionListener action = new ActionListener() {

            public void actionPerformed(ActionEvent evt) {
                System.out.println("Hello!");
                p.repaint();
            }
        };

        t = new Timer(50, action);
        p = new JPanel() {

            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                final Graphics2D gD = (Graphics2D) g;
                moveBALL();
                gD.drawOval(x, y, 25, 25);

                p.addMouseListener(new MouseListener() {

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        System.out.println("a");
                    }

                    @Override
                    public void mousePressed(MouseEvent e) {
                        System.out.println("b");
                    }

                    @Override
                    public void mouseExited(MouseEvent e) {
                        System.out.println("c");
                    }

                    @Override
                    public void mouseEntered(MouseEvent e) {
                        System.out.println("d");
                    }

                    @Override
                    public void mouseClicked(MouseEvent e) {
                        gD.drawRect(e.getX(), e.getY(), 10, 60);
                        gD.setColor(Color.green);
                        System.out.println("clicked");
                    }
                });
            }

            void moveBALL() {
                x = x + xspeed;
                y = y + yspeed;
                if (x < 0) {
                    x = 0;
                    xspeed = -xspeed;
                } else if (x > p.getWidth() - 20) {
                    x = p.getWidth() - 20;
                    xspeed = -xspeed;
                }
                if (y < 0) {
                    y = 0;
                    yspeed = -yspeed;
                } else if (y > p.getHeight() - 20) {
                    y = p.getHeight() - 20;
                    yspeed = -yspeed;
                }
            }
        };
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new testclass().setVisible(true);
                p.setBackground(Color.WHITE);
            }
        });
    }
}

在此程序中实现 mouseListener() 的正确方法是什么? 谢谢。

最佳答案

对当前代码的一些建议:

  • 观看类命名方案,即 testclass 应该是 TestClass 甚至更好的 Test (但这只是挑剔)。所有类名均以大写字母开头,此后的每个新单词均大写。

  • 不必要时不要扩展 JFrame

  • 不要在 JFrame 上调用 setBounds,而是使用适当的 LayoutManager 和/或覆盖 getPreferredSize() JPanel 并返回适合其内容的尺寸。

  • 在将 JFrame 设置为可见之前,始终调用 pack()(考虑到上述情况)。

  • 使用 MouseAdapterMouseListener

  • 不要在paintComponent中调用moveBall(),而是在Timer中调用它,它会重新绘制屏幕,​​这不仅是更好的设计但我们也不应该在绘制方法中执行可能长时间运行的任务。

至于你的问题,我认为你的逻辑有点扭曲。

一种方法是使用自己的自定义类(这将允许我们存储颜色等属性)来替换Rectangle(或Rectangle2D)。您的也会有自己的类,该类具有moveBall()方法及其属性,例如xy位置等。在每次 repaint() 上,您的 JPanel 都会调用移动球的方法,JPanel 本身可以包装 moveBall () 在它自己的公共(public)方法中,我们可以从重新绘制屏幕的计时器中调用该方法。

以下是实现了上述修复的代码示例(请对其进行分析,如果您有任何问题,请告诉我):

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

关于Java - PaintComponent 中的 MouseListener 操作事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14068472/

相关文章:

java - setImageBitmap() 比 image.setImageDrawable()、image.setImageResource() 慢

java - 不同类型的 ArrayList 的总和

java - 比较 SWT 和 SWING

java - JOptionPane 显示不正确?

events - 如何在 Flutter 上实现事件监听器或委托(delegate)

Carbon - OS X - 使用 CGEventPost 发送修改后的按键事件

c# - 处理从主窗口中的模态对话框引发的冒泡事件

java - 尝试将 webtable 导出到 Excel 时出现无效选择器错误

未知数量元素的 Java 布局

java - 是否可以将 Android 包导入普通的 Java 代码