Java – paintComponent中的MouseListener Action事件

这里我有一个代码,使用paintComponent在mouseClicked位置绘制一个矩形。我可以得到输出消息,但任何与图形和.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  p.getWidth() - 20) { x = p.getWidth() - 20; xspeed = -xspeed; } 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和/或覆盖JPanel getPreferredSize()并返回适合其内容的维度。

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

  • 使用MouseAdapterMouseListener

  • 不要在paintComponent调用moveBall()而是在重新绘制屏幕的Timer调用它,不仅设计略微好一些,而且我们也不应该在绘制方法中执行长时间运行的任务。

至于你的问题,我认为你的逻辑有点偏差。

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

以下是实施上述修复程序的代码示例(请分析一下,如果您有任何问题请告诉我):

在此处输入图像描述

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

首先,每次swing需要重绘组件时都会调用paint组件。
每次调用绘图时,您都会向面板添加一个新的鼠标侦听器实例。

只需移动线
p.addMouseListener(new MouseListener(){…}
优选在面板初始化之后,从涂料组分中取出。

默认模板是

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

希望这可以帮助。