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()
,然后将其设置为可见(考虑到上述情况)。 -
使用
MouseAdapter
与MouseListener
-
不要在
paintComponent
调用moveBall()
而是在重新绘制屏幕的Timer
调用它,不仅设计略微好一些,而且我们也不应该在绘制方法中执行长时间运行的任务。
至于你的问题,我认为你的逻辑有点偏差。
一种方法是看到Rectangle
(或Rectangle2D
)被它自己的自定义类替换(这将允许我们存储颜色等属性)。 你的球也有自己的类,它有方法moveBall()
及其属性,如x
和y
位置等。在每个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 });
希望这可以帮助。