Java Swing mousePressed 和 getSource() 未在 JPanel 上显示绘制的形状
Java Swing mousePressed and getSource() not showing drawed shapes on JPanel
我目前正在尝试开发一个谜题。我得到的只是我的应用程序以及我的运动场和游戏部件。下一步是点击我的一个游戏部件到 select 它并能够用箭头键移动它(此外我只想让它们移动,如果下一步 - 这将是 100 像素- 不包含任何其他游戏件)。
我目前 运行 遇到的问题:在我的主要 JPanel
上使用 addMouseListener()
,然后仅 return 在我的演奏中使用 getSource()
-字段(在我的代码中称为 View
),但我需要它 return 所需的游戏部件(例如 topLeft
)。我已经尝试将 getSource()
转换为 Piece
但这不起作用 (Cannot cast View to Piece
).
所以,我需要找到一种方法来添加一个鼠标侦听器,return是被点击的游戏部件,这样我就可以更改位置并检查是否与任何其他游戏发生碰撞-片。提前致谢!
感谢@camickr 编辑了代码。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Puzzle {
public static void main(String[] args) {
SwingUtilities.invokeLater(Puzzle::new);
}
private final static int[] SHAPE_X = { -100, 100, 100, 0, 0, -100 };
private final static int[] SHAPE_Y = { -100, -100, 0, 0, 100, 100 };
public Puzzle() {
JFrame frame = new JFrame("Puzzle");
frame.setSize(400, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
View view = new View();
frame.setContentPane(view);
view.addMouseListener(new MouseAdapterMod(view));
Shape polyShape = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
Piece topLeft = new Piece(Color.YELLOW, polyShape, 0, 100, 100);
view.pieces.add(topLeft);
Piece topRight = new Piece(Color.CYAN, polyShape, 90, 300, 100);
view.pieces.add(topRight);
Piece bottomRight = new Piece(Color.GREEN, polyShape, 180, 300, 300);
view.pieces.add(bottomRight);
Piece bottomLeft = new Piece(Color.RED, polyShape, 270, 100, 300);
view.pieces.add(bottomLeft);
Piece square = new Piece(Color.ORANGE, new Rectangle(200, 200), 0, 100, 100);
view.pieces.add(square);
frame.setVisible(true);
}
}
class View extends JPanel {
final List<Piece> pieces = new ArrayList<>();
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gc = (Graphics2D) g;
for (Piece piece : pieces) {
piece.draw(gc);
}
}
}
class Piece {
final Color color;
final Shape shape;
final int angle;
int x;
int y;
Piece(Color color, Shape shape, int angle, int x, int y) {
this.color = color;
this.shape = shape;
this.angle = angle;
this.x = x;
this.y = y;
}
void draw(Graphics2D gc) {
AffineTransform tf = gc.getTransform();
gc.translate(x, y);
gc.rotate(Math.toRadians(angle));
gc.setColor(color);
gc.fill(shape);
gc.setTransform(tf);
}
Shape getShape() {
return shape;
}
}
class MouseAdapterMod extends MouseAdapter {
final View view;
public MouseAdapterMod(View view) {
this.view = view;
}
@Override
public void mousePressed(MouseEvent e) {
for(Piece piece : view.pieces) {
if(piece.getShape().contains(e.getX(), e.getY())) {
System.out.println("yes");
}
}
}
}
So, I need to find a way to add a mouse listener which returns the gaming-piece that was clicked
您使用 MouseEvent 中的 getX() 和 getY() 方法。
然后遍历 "pieces" ArrayList 并在每个 Piece
中包含的 Shape
上调用 contains(...
方法以查看鼠标点是否包含在片。
因此,您还需要向 "Piece" class 添加一个 getShape(...)
方法,以便您可以访问每个 Piece
的 Shape
。
编辑:
所以你的基本逻辑可能是这样的:
//Shape polyShape = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
//Piece topLeft = new Piece(Color.YELLOW, polyShape, 0, 100, 100);
Polygon topLeftPolygon = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
topLeftPolygon.translate(100, 100);
//topLeftPolygon = ShapeUtils.rotate(...); // do rotation when required
Piece topLeft = new Piece(Color.YELLOW, topLeftPolygon);
那么draw(..)方法中的绘画代码就是:
gc.setColor(color);
gc.fill(shape);
无需转换或翻译。
编辑 2:
所以使用形状:
//topLeftPolygon = ShapeUtils.rotate(...); // do rotation when required
//Piece topLeft = new Piece(Color.YELLOW, topLeftPolygon);
Shape topLeftShape = ShapeUtils.rotate(...); // do rotation when required
Piece topLeft = new Piece(Color.YELLOW, topLeftShape);
这当前与您的 Piece class 匹配,它无论如何都需要一个 Shape 对象。请考虑所建议的概念,不要假设发布的代码是完美的,因为它显然还没有经过测试。
我看到您使用了我的 from this 作为您的益智游戏的基础,而不是继续使用您自己的代码。明白,我给了你一个最小的、完整的、可验证的例子,用于在 JPanel
上绘制形状。我从来没有说过适合直接使用;事实上,通过使示例 "minimal" 它可能导致扩展代码以支持诸如命中测试之类的事情变得更加困难。但是既然你选择了以我的代码为基础继续...
您的命中测试问题来自于鼠标点击是在视图的坐标系中,但形状被平移并旋转到其他各种位置以进行绘制。您可以通过反转转换来解决此问题,将鼠标位置转换为形状的坐标系,然后使用 Shape.contains(Point2D)
.
class Piece {
// ... omitted for brevity ...
public boolean hitTest(Point point) {
AffineTransform tf = new AffineTransform();
tf.translate(x, y);
tf.rotate(Math.toRadians(angle));
try {
Point2D pnt = tf.inverseTransform(point, null);
return shape.contains(pnt);
} catch (NoninvertibleTransformException e) {
return false;
}
}
}
然后,简单地遍历每一个片段,并询问它是否在鼠标的位置之下。
class View extends JPanel {
// ... omitted for brevity ...
Piece hitTest(MouseEvent e) {
Point pnt = e.getPoint();
for (Piece piece : pieces) {
if (piece.hitTest(pnt))
return piece;
}
return null;
}
}
请注意,我在这里 return 使用 Piece
,而不是 Shape
。由于 5 件中有 4 件使用相同的 polyShape
形状,这不是很有用。
可以使用 Java8 流来缩短 hitTest()
:
Piece hitTest(MouseEvent e) {
final Point pnt = e.getPoint();
return pieces.stream()
.filter(piece -> piece.hitTest(pnt))
.findFirst()
.orElse(null);
}
如果棋子可以重叠,则出现在最上面的是最后绘制的棋子。 findFirst()
将 return 在给定的鼠标点绘制最底部的部分,而不是最顶部的部分。以下更改将纠正该行为:
Piece hitTest(MouseEvent e) {
final Point pnt = e.getPoint();
return pieces.stream()
.filter(piece -> piece.hitTest(pnt))
.reduce((first, second) -> second)
.orElse(null);
}
我目前正在尝试开发一个谜题。我得到的只是我的应用程序以及我的运动场和游戏部件。下一步是点击我的一个游戏部件到 select 它并能够用箭头键移动它(此外我只想让它们移动,如果下一步 - 这将是 100 像素- 不包含任何其他游戏件)。
我目前 运行 遇到的问题:在我的主要 JPanel
上使用 addMouseListener()
,然后仅 return 在我的演奏中使用 getSource()
-字段(在我的代码中称为 View
),但我需要它 return 所需的游戏部件(例如 topLeft
)。我已经尝试将 getSource()
转换为 Piece
但这不起作用 (Cannot cast View to Piece
).
所以,我需要找到一种方法来添加一个鼠标侦听器,return是被点击的游戏部件,这样我就可以更改位置并检查是否与任何其他游戏发生碰撞-片。提前致谢!
感谢@camickr 编辑了代码。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Puzzle {
public static void main(String[] args) {
SwingUtilities.invokeLater(Puzzle::new);
}
private final static int[] SHAPE_X = { -100, 100, 100, 0, 0, -100 };
private final static int[] SHAPE_Y = { -100, -100, 0, 0, 100, 100 };
public Puzzle() {
JFrame frame = new JFrame("Puzzle");
frame.setSize(400, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
View view = new View();
frame.setContentPane(view);
view.addMouseListener(new MouseAdapterMod(view));
Shape polyShape = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
Piece topLeft = new Piece(Color.YELLOW, polyShape, 0, 100, 100);
view.pieces.add(topLeft);
Piece topRight = new Piece(Color.CYAN, polyShape, 90, 300, 100);
view.pieces.add(topRight);
Piece bottomRight = new Piece(Color.GREEN, polyShape, 180, 300, 300);
view.pieces.add(bottomRight);
Piece bottomLeft = new Piece(Color.RED, polyShape, 270, 100, 300);
view.pieces.add(bottomLeft);
Piece square = new Piece(Color.ORANGE, new Rectangle(200, 200), 0, 100, 100);
view.pieces.add(square);
frame.setVisible(true);
}
}
class View extends JPanel {
final List<Piece> pieces = new ArrayList<>();
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gc = (Graphics2D) g;
for (Piece piece : pieces) {
piece.draw(gc);
}
}
}
class Piece {
final Color color;
final Shape shape;
final int angle;
int x;
int y;
Piece(Color color, Shape shape, int angle, int x, int y) {
this.color = color;
this.shape = shape;
this.angle = angle;
this.x = x;
this.y = y;
}
void draw(Graphics2D gc) {
AffineTransform tf = gc.getTransform();
gc.translate(x, y);
gc.rotate(Math.toRadians(angle));
gc.setColor(color);
gc.fill(shape);
gc.setTransform(tf);
}
Shape getShape() {
return shape;
}
}
class MouseAdapterMod extends MouseAdapter {
final View view;
public MouseAdapterMod(View view) {
this.view = view;
}
@Override
public void mousePressed(MouseEvent e) {
for(Piece piece : view.pieces) {
if(piece.getShape().contains(e.getX(), e.getY())) {
System.out.println("yes");
}
}
}
}
So, I need to find a way to add a mouse listener which returns the gaming-piece that was clicked
您使用 MouseEvent 中的 getX() 和 getY() 方法。
然后遍历 "pieces" ArrayList 并在每个 Piece
中包含的 Shape
上调用 contains(...
方法以查看鼠标点是否包含在片。
因此,您还需要向 "Piece" class 添加一个 getShape(...)
方法,以便您可以访问每个 Piece
的 Shape
。
编辑:
所以你的基本逻辑可能是这样的:
//Shape polyShape = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
//Piece topLeft = new Piece(Color.YELLOW, polyShape, 0, 100, 100);
Polygon topLeftPolygon = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
topLeftPolygon.translate(100, 100);
//topLeftPolygon = ShapeUtils.rotate(...); // do rotation when required
Piece topLeft = new Piece(Color.YELLOW, topLeftPolygon);
那么draw(..)方法中的绘画代码就是:
gc.setColor(color);
gc.fill(shape);
无需转换或翻译。
编辑 2:
所以使用形状:
//topLeftPolygon = ShapeUtils.rotate(...); // do rotation when required
//Piece topLeft = new Piece(Color.YELLOW, topLeftPolygon);
Shape topLeftShape = ShapeUtils.rotate(...); // do rotation when required
Piece topLeft = new Piece(Color.YELLOW, topLeftShape);
这当前与您的 Piece class 匹配,它无论如何都需要一个 Shape 对象。请考虑所建议的概念,不要假设发布的代码是完美的,因为它显然还没有经过测试。
我看到您使用了我的 JPanel
上绘制形状。我从来没有说过适合直接使用;事实上,通过使示例 "minimal" 它可能导致扩展代码以支持诸如命中测试之类的事情变得更加困难。但是既然你选择了以我的代码为基础继续...
您的命中测试问题来自于鼠标点击是在视图的坐标系中,但形状被平移并旋转到其他各种位置以进行绘制。您可以通过反转转换来解决此问题,将鼠标位置转换为形状的坐标系,然后使用 Shape.contains(Point2D)
.
class Piece {
// ... omitted for brevity ...
public boolean hitTest(Point point) {
AffineTransform tf = new AffineTransform();
tf.translate(x, y);
tf.rotate(Math.toRadians(angle));
try {
Point2D pnt = tf.inverseTransform(point, null);
return shape.contains(pnt);
} catch (NoninvertibleTransformException e) {
return false;
}
}
}
然后,简单地遍历每一个片段,并询问它是否在鼠标的位置之下。
class View extends JPanel {
// ... omitted for brevity ...
Piece hitTest(MouseEvent e) {
Point pnt = e.getPoint();
for (Piece piece : pieces) {
if (piece.hitTest(pnt))
return piece;
}
return null;
}
}
请注意,我在这里 return 使用 Piece
,而不是 Shape
。由于 5 件中有 4 件使用相同的 polyShape
形状,这不是很有用。
可以使用 Java8 流来缩短 hitTest()
:
Piece hitTest(MouseEvent e) {
final Point pnt = e.getPoint();
return pieces.stream()
.filter(piece -> piece.hitTest(pnt))
.findFirst()
.orElse(null);
}
如果棋子可以重叠,则出现在最上面的是最后绘制的棋子。 findFirst()
将 return 在给定的鼠标点绘制最底部的部分,而不是最顶部的部分。以下更改将纠正该行为:
Piece hitTest(MouseEvent e) {
final Point pnt = e.getPoint();
return pieces.stream()
.filter(piece -> piece.hitTest(pnt))
.reduce((first, second) -> second)
.orElse(null);
}