我正在做一个涉及 JSwing 的项目。该项目由一个 JLayeredPane 组成,该 JLayeredPane 包含一个 JScrollPane 和一个游戏板(JPanel 与 JPanels 与 JLabel)。
我的问题是我向 JLayeredPane 添加了一个自定义鼠标侦听器。但是,当我单击 JScrollPane 区域时,侦听器似乎没有注册。但是,如果我点击其他地方,它确实如此。谁能解释为什么会这样?
提前致谢!
创建面板的代码 + 将侦听器添加到 JLayeredPane:
private void initPanels() {
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setLayout(new BorderLayout());
layeredPane.add(makeBoardPanel(), BorderLayout.CENTER, JLayeredPane.DEFAULT_LAYER);
JPanel panel = new JPanel(new BorderLayout());
panel.add(makeButtonPanel(), BorderLayout.WEST);
panel.add(makeDeckPanel(), BorderLayout.EAST);
layeredPane.add(panel, BorderLayout.SOUTH, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(makeMeeplePanel(), BorderLayout.NORTH, JLayeredPane.DEFAULT_LAYER);
//TODO: fix adapter + add others;
TileMouseAdapter tileMouseAdapter = new TileMouseAdapter(layeredPane);
layeredPane.addMouseListener(tileMouseAdapter);
layeredPane.addMouseMotionListener(tileMouseAdapter);
add(layeredPane);
myController.reset(TileDeck.getDemo(), NUM_PLAYERS); //sets up game
}
使用 JScrollPane 制作 Board 的代码:
private JScrollPane makeBoardPanel() {
JScrollPane scrollPane = new JScrollPane(CarcassoneBoard.getInstance());
CarcassoneBoard.getInstance().setScrollPane(scrollPane);
return scrollPane;
}
这是最后一行的代码 (myController.reset( ... ))
public void reset(Map<TileFactory, Integer> deck, int numPlayers) {
myDeck.reset(deck);
myBoard.reset(myDeck.getDeckSize()); //only panel contained in JScrollPane
myMeeplePanel.reset(numPlayers);
}
myBoard 的重置方法...
public void reset(int num_tiles) {
super.removeAll();
NUM_TILES = num_tiles;
BOARD_SIZE = (int) Math.ceil(num_tiles / 2.0);
setLayout(new GridLayout(BOARD_SIZE, BOARD_SIZE, 1, 1));
setPreferredSize(new Dimension(BOARD_SIZE * TILE_WIDTH, BOARD_SIZE * TILE_HEIGHT));
STARTING_TILE = new BubbleCity((int) Math.ceil(BOARD_SIZE / 2.0 - 1), (int) Math.ceil(BOARD_SIZE / 2.0 - 1));
myTiles = new TilePanel[BOARD_SIZE][BOARD_SIZE];
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
myTiles[i][j] = new TilePanel(i, j, new EmptyTile(i, j));
add(myTiles[i][j]);
}
}
myTiles[STARTING_TILE.getRow()][STARTING_TILE.getCol()].setTile(STARTING_TILE);
revalidate();
repaint();
}
这是鼠标侦听器的代码:
public class TileMouseAdapter extends MouseAdapter {
private JLayeredPane myLayeredPane;
private Tile myTile;
private TilePanel myClickedPanel;
public TileMouseAdapter(JLayeredPane layeredPane) {
myLayeredPane = layeredPane;
}
private void reset() {
if (myTile != null) {
myLayeredPane.remove(myTile);
myLayeredPane.revalidate();
myLayeredPane.repaint();
}
myTile = null;
myClickedPanel = null;
}
//point p is a point relative to myLayeredPane...
public Point translatePoint(Component component, Point p) {
return SwingUtilities.convertPoint(myLayeredPane, p, component);
}
//point p is relative to the screen (event.getLocationOnScree()). We want to check if that point is in component.
public boolean containsPoint(Component component, Point p) {
Point translated = translatePoint(component, p );
return translated.getX() > 0 && translated.getY() > 0
&& translated.getX() < component.getWidth() && translated.getY() < component.getHeight();
}
@Override
public void mouseClicked(MouseEvent event) {
}
@Override
public void mousePressed(MouseEvent event) {
//no registering jscrollpane?
CarcassoneBoard board = CarcassoneBoard.getInstance();
TileDeck deck = TileDeck.getInstance();
System.out.println("pressed!");
if (containsPoint(deck, event.getPoint())) {
System.out.println("deck");
myClickedPanel = deck;
myTile = myClickedPanel.getTile();
}
else if (containsPoint(board.getScrollPane().getViewport(), event.getPoint())) {
System.out.println("board");
Component component = board.getComponentAt(translatePoint(board.getScrollPane().getViewport(), event.getPoint()));
if (component instanceof CarcassoneBoard) {return;} //user clicked in between tiles...do nothing.
myClickedPanel = (TilePanel) component;
myTile = myClickedPanel.getTile();
}
if (myTile == null || myTile instanceof EmptyTile || !myTile.isDraggable()) {
//TODO: scroll with drag!
reset();
return;
}
myClickedPanel.setEmpty(); //panel will set an empty tile automatically and remove myTile...
int x = event.getPoint().x - myTile.getWidth() / 2;
int y = event.getPoint().y - myTile.getHeight() / 2;
myTile.setLocation(x, y);
myLayeredPane.revalidate();
myLayeredPane.repaint();
try {
myLayeredPane.add(myTile, JLayeredPane.DRAG_LAYER);
myLayeredPane.revalidate();
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 (myTile == null) {
return;
}
int x = event.getPoint().x - myTile.getWidth() / 2;
int y = event.getPoint().y - myTile.getHeight() / 2;
myTile.setLocation(x, y);
myLayeredPane.revalidate();
myLayeredPane.repaint();
}
@Override
public void mouseReleased(MouseEvent event) {
if (myTile == null) {// || !myTile.isDraggable()) {
return; //do nothing...board scrolling
}
CarcassoneBoard board = CarcassoneBoard.getInstance();
myLayeredPane.remove(myTile);
TilePanel dropped = (TilePanel) board.getComponentAt(translatePoint(board.getScrollPane().getViewport(), event.getPoint()));
if (dropped == null) {
//reset tile to original spot
myClickedPanel.setTile(myTile);
reset();
return;
}
dropped.setTile(myTile);
reset();
}
}
笔记:
我将 makeBoardPanel() 更改为:
private JPanel makeBoardPanel() {
return CarcassoneBoard.getInstance();
}
并且听众似乎在板上注册了点击,这让我相信它与 JScrollPane 有关。我通过在 mousePressed 方法头之后放置一个打印语句来确定这一点。当我点击板子时,它在抱怨我引用了稍后在代码中不存在的 JScrollPane 之前打印了声明:/