0

我正在做一个涉及 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 之前打印了声明:/

4

0 回答 0