我目前正在尝试为一款名为Carcassone的游戏创建一个应用程序,但是我在使用JLayeredPane和MouseAdapters时遇到了问题。
目前我有一个JLayeredPane,它包含一个带有GridLayout的JPanel,用作游戏板。 GridLayout的每个单元格都包含一个JPanel,其中包含一个JLabel,用于表示板上的图块。 (空的瓷砖只是一个带有黑色方块作为图像的JLabel)。
我在JLayeredPane中添加了一个自定义鼠标适配器(TileMouseAdapter),允许用户在游戏板周围移动磁贴(鼠标按下 - 拖动 - 释放)或旋转磁贴(鼠标单击)。 (要测试单击下一个切片按钮并在显示的切片周围移动,单击提交按钮后,如果切片是有效移动,则切片将不再可拖动)。这一切都完美无缺,直到我添加下一部分。
现在我想在屏幕顶部的JLayeredPane中添加一个单独的JPanel。此部分应该包含玩家可以放置在瓷砖上的游戏块。我还希望JPanel能够保存游戏棋子,以便玩家可以将棋子拖到棋子上。但是,当我创建此面板并将其添加到JLayeredPane时,上一节中的鼠标适配器不再正常工作。例如,如果单击图块的底部,则不再识别您正在单击图块。如果您单击每个图块的上半部分,它将仅选择图块。此外,如果您单击图块的底部,有时它将选择下面的图块。也就是说,似乎选择瓷砖的机制似乎向上移动了大约一半的瓷砖。 任何人都可以找出这个问题的解释/可能的解决方案吗? 谢谢!
下面的代码是我用来创建JLayeredPane的代码,其中包含用于棋盘的JPanel(myBoardPanel)以及游戏棋子的面板(makeMeeplePanel())
private JLayeredPane makeBoardPanel() {
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setLayout(new BorderLayout());
myBoardPanel = new CarcassoneBoardPanel(layeredPane);
layeredPane.add(makeMeeplePanel(), BorderLayout.NORTH, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(myBoardPanel, BorderLayout.CENTER, JLayeredPane.DEFAULT_LAYER);
TileMouseAdapter tileMouseAdapter = new TileMouseAdapter(layeredPane);
//MeepleMouseAdapter meepleMouseAdapter = new MeepleMouseAdapter(layeredPane);
layeredPane.addMouseListener(tileMouseAdapter);
layeredPane.addMouseMotionListener(tileMouseAdapter);
//layeredPane.addMouseListener(meepleMouseAdapter);
//layeredPane.addMouseMotionListener(meepleMouseAdapter);
return layeredPane;
}
这是我的游戏板自定义鼠标适配器:
package gui;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import tiles.*;
public class TileMouseAdapter extends MouseAdapter {
private JLayeredPane myLayeredPane;
private CarcassoneBoardPanel myBoard;
private Tile dragLabel;
private JPanel clickedPanel;
public TileMouseAdapter(JLayeredPane layeredPane) {
myLayeredPane = layeredPane;
myBoard = (CarcassoneBoardPanel) layeredPane.getComponents()[1];
}
private void reset() {
if (dragLabel != null) {
myLayeredPane.remove(dragLabel);
myLayeredPane.revalidate();
myLayeredPane.repaint();
}
dragLabel = null;
clickedPanel = null;
}
@Override
public void mouseClicked(MouseEvent event) {
clickedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
if (clickedPanel == null) {
reset();
return;
}
Component[] components = clickedPanel.getComponents();
if (!(components[0] instanceof Tile) || components[0] instanceof EmptyTile || !((Tile) components[0]).isDraggable()) {
return;
}
dragLabel = (Tile) components[0];
dragLabel.rotate();
clickedPanel.revalidate();
clickedPanel.repaint();
reset();
}
@Override
public void mousePressed(MouseEvent event) {
clickedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
System.out.println(event.getPoint());
if (clickedPanel == null) {
reset();
return;
}
Component[] components = clickedPanel.getComponents();
if (!(components[0] instanceof Tile) || (components[0] instanceof EmptyTile) || !((Tile) components[0]).isDraggable()) {
return;
}
dragLabel = (Tile) components[0];
clickedPanel.remove(dragLabel);
clickedPanel.add(new EmptyTile(dragLabel.getRow(), dragLabel.getCol()));
clickedPanel.revalidate();
clickedPanel.repaint();
int x = event.getPoint().x - dragLabel.getWidth() / 2;
int y = event.getPoint().y - dragLabel.getHeight() / 2;
dragLabel.setLocation(x, y);
try {
myLayeredPane.add(dragLabel, JLayeredPane.DRAG_LAYER);
myLayeredPane.repaint();
} catch (IllegalArgumentException e) {
//TODO: deal with this?
//gives error for some unknown reason, but doesnt effect anything? ignore...dumb error cus jswing sucks
}
}
@Override
public void mouseDragged(MouseEvent event) {
if (dragLabel == null) {
return;
}
int x = event.getPoint().x - dragLabel.getWidth() / 2;
int y = event.getPoint().y - dragLabel.getHeight() / 2;
dragLabel.setLocation(x, y);
myLayeredPane.revalidate();
}
@Override
public void mouseReleased(MouseEvent event) {
//TODO: make sure cannot place tile on already occupied panel...
if (dragLabel == null || !dragLabel.isDraggable()) {
return;
}
myLayeredPane.remove(dragLabel);
myLayeredPane.revalidate();
myLayeredPane.repaint();
JPanel droppedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
if (droppedPanel == null) {
clickedPanel.removeAll();
clickedPanel.add(dragLabel);
clickedPanel.revalidate();
reset();
return;
}
dragLabel.setPosition(((Tile) droppedPanel.getComponents()[0]).getRow(), ((Tile) droppedPanel.getComponents()[0]).getCol());
droppedPanel.removeAll();
droppedPanel.add(dragLabel);
droppedPanel.revalidate();
reset();
}
}
如果您需要更多信息/代码,请告诉我。这是我第一次使用这个网站,很抱歉,如果我没有提供足够的解释等等...... 谢谢!
答案 0 :(得分:2)
你的问题在这里:
@Override
public void mouseClicked(MouseEvent event) {
clickedPanel = (JPanel) myBoard.getComponentAt(event.getPoint());
event.getPoint()
将返回Point
相对于您的鼠标监听器注册的layeredPane
。 myBoard.getComponentAt()
会在相对于myBoard
组件的点处返回组件,该组件位于layeredPane.getComponents()[1]
的分层窗格中。