Возникли проблемы с перетаскиванием JLabel из одной JPanel в другую

#java #swing #jpanel #jlabel #chess

#java #swing #jpanel #jlabel #шахматы

Вопрос:

Я пытаюсь разработать шахматный движок Java, используя Swing для графического интерфейса, и за последние пару дней я обнаружил некоторые неудачи. Движок уже полностью функционален и отлично работает с перемещениями по щелчку (1 щелчок по плитке-JPanel с фигурой, которую вы хотите переместить, еще один щелчок по плитке-JPanel, где вы хотите разместить фигуру). Теперь я готов сделать еще один шаг и решил реализовать перетаскивание (щелкните и удерживайте мышь, перетащите и отпустите нужную JPanel).

Вот где я нахожу свои проблемы. Мой класс move имеет следующие аргументы: конфигурация шахматной доски, начальная плитка для перемещения и конечная плитка. При нажатии мыши он принимает идентификатор исходной плитки, но когда я отпускаю его, то, что будет идентификатором целевой плитки, вместо этого также является идентификатором исходной плитки. Это заставляет мой движок думать, что я пытаюсь переместить фрагменты на одну и ту же плитку, что приводит к незаконному перемещению. Я попытался использовать destinationTile = chessBoard.getTile(tileId) ту же концепцию, которую я использовал для перемещений по щелчку, но вместо этого он использует исходную плитку. Я пробовал использовать TilePanel obj = (TilePanel)e.getSource(); destinationTile = chessBoard.getTile(obj.getTileId()); и при этом как исходная, так и целевая плитка получают значение идентификатора элемента? Поэтому, если я попытаюсь перетащить пешку, они оба получат «P» в качестве значения, если я попытаюсь переместить ферзя, они получат «Q». Так что да, я полностью потерян.

Вторая проблема, с которой я сталкиваюсь, заключается в том, что при перетаскивании фрагмента-JLabel он ограничен границами фрагмента-JPanel, в котором он находится. Этого следовало ожидать, поэтому я попытался использовать JLayeredPane. Мой подход заключался в том, чтобы клонировать перемещенную часть-JLabel, установить исходную невидимой. Добавьте клонированный в JLayeredPane.DRAG_LAYER , перетащите его, следуя указаниям мыши. И при выпуске, если данное перемещение было законным, поместите эту JLabel на целевую плитку JPanel и удалите невидимую JLabel на исходной плитке. Это также не увенчалось успехом, поскольку, как бы я ни пытался добавить JLabel в DRAG_LAYER, я не мог заставить его работать. Что бы я ни пробовал, я не мог заставить изображение части следовать за моим курсором по доске.

Вот большая часть моего класса Tile со всеми обработчиками MouseEvent:

 private class TilePanel extends JPanel {

        private final int tileId;

        public int getTileId() {
            return tileId;
        }

        TilePanel(final BoardPanel boardPanel, final int tileId) throws IOException {
            super(new GridBagLayout());
            this.tileId = tileId;
            setPreferredSize(TILE_PANEL_DIMENSION);
            assignTileColor();
            assignTilePieceIcon(chessBoard);
            highlightTileBorder(chessBoard);
            addMouseListener(new MouseListener() {

                @Override
                public void mouseClicked(final MouseEvent e) {
                    if(isRightMouseButton(e)) {
                        sourceTile = null;
                        destinationTile = null;
                        humanMovedPiece = null;
                        try {
                            boardPanel.drawBoard(chessBoard);
                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                        System.out.println("piece deselected");
                    }
                    else if (isLeftMouseButton(e)) {
                        if(sourceTile == null) {
                            //first click
                            sourceTile = chessBoard.getTile(tileId);
                            humanMovedPiece = sourceTile.getPiece();
                            if (humanMovedPiece == null) {
                                sourceTile = null;
                            }
                            System.out.println("piece selected");
                        }
                        else {
                            //second click
                            destinationTile = chessBoard.getTile(tileId);
                            final Move move = Move.MoveFactory.createMove(chessBoard, sourceTile.getTileCoordinate(), destinationTile.getTileCoordinate());
                            final MoveTransition transition = chessBoard.getCurrentPlayer().makeMove(move);
                            if (transition.getMoveStatus() == MoveStatus.DONE) {
                                chessBoard = transition.getTransitionBoard();
                                moveLog.addMove(move);
                                SFXUtils.playSound("move");
                                System.out.println(chessBoard);
                                System.out.println("█████ move done: "   move.toString()   " █████");

                            }
                            sourceTile = null;
                            destinationTile = null;
                            humanMovedPiece = null;

                        }
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    gameHistoryPanel.redo(chessBoard, moveLog);
                                    takenPiecesPanel.redo(moveLog);
                                    boardPanel.drawBoard(chessBoard);
                                } catch (IOException ioException) {
                                    ioException.printStackTrace();
                                }
                            }
                        });
                    }
                }

                @Override
                public void mousePressed(final MouseEvent e) {
                    if(sourceTile == null) {
                        //first click
                        sourceTile = chessBoard.getTile(tileId);
                        System.out.println(tileId);
                        System.out.println(sourceTile.getTileCoordinate());
                        humanMovedPiece = sourceTile.getPiece();
                        if (humanMovedPiece == null) {
                            sourceTile = null;
                        }
                        System.out.println("piece selected");
                    }
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                gameHistoryPanel.redo(chessBoard, moveLog);
                                takenPiecesPanel.redo(moveLog);
                                boardPanel.drawBoard(chessBoard);
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                        }
                    });
                }

                @Override
                public void mouseReleased(final MouseEvent e) {

                   /* TilePanel obj = (TilePanel)e.getSource();
                    destinationTile = chessBoard.getTile(obj.getTileId());*/
                    destinationTile = chessBoard.getTile(tileId);

                    final Move move = Move.MoveFactory.createMove(chessBoard, sourceTile.getTileCoordinate(), destinationTile.getTileCoordinate());

                    final MoveTransition transition = chessBoard.getCurrentPlayer().makeMove(move);

                    if (transition.getMoveStatus() == MoveStatus.DONE) {
                        chessBoard = transition.getTransitionBoard();
                        moveLog.addMove(move);
                        SFXUtils.playSound("move");
                        System.out.println(chessBoard);
                        System.out.println("█████ move done: "   move.toString()   " █████");

                    }
                    sourceTile = null;
                    destinationTile = null;
                    humanMovedPiece = null;

                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                gameHistoryPanel.redo(chessBoard, moveLog);
                                takenPiecesPanel.redo(moveLog);
                                boardPanel.drawBoard(chessBoard);
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                        }
                    });

                }

                @Override
                public void mouseEntered(final MouseEvent e) {

                }

                @Override
                public void mouseExited(final MouseEvent e) {

                }
            });

            addMouseMotionListener(new MouseMotionListener() {

                @Override
                public void mouseDragged(final MouseEvent e) {
                    System.out.println("im draggin");
                    TilePanel obj = (TilePanel)e.getSource();
                    JLabel draggedPieceImageLabel = (JLabel) obj.getComponent(0);
                    //obj.getComponent(0).setVisible(false);
                    draggedPieceImageLabel.setLocation(e.getX()-25,e.getY()-25);
                    add(draggedPieceImageLabel);
                }

                @Override
                public void mouseMoved(MouseEvent e) {

                }
            });


            validate();
        }
 

Комментарии:

1. Ваш MouseMotionListener выполняет add(draggedPieceImageLabel); . Перетаскиваемый фрагмент не может находиться как в JLayeredPane, так и в TilePanel. Он нужен только в JLayeredPane.

2. Я помню, как много лет назад у меня была именно эта проблема. Я думаю, что мое решение состояло в том, чтобы просто использовать 1 JPanel для всей платы с GridLayout. Вы захотите переопределить paintBackground, но во многих отношениях это упрощает задачу.

3. Может быть, это уместно? Перетаскивание и передача данных , что является уроком в trail под названием » Создание графического интерфейса пользователя с помощью JFC / Swing «, который является частью руководств Oracle по Java.

4. @VGR Я не упомянул, что опубликованный мной код — это версия, в которой не используется JLayeredPane. При использовании JLayeredPane я пытаюсь добавить к нему JLabel, но безрезультатно. Я сделал это так boardLayeredPane.add(draggedPieceImageLabel, JLayeredPane.DRAG_LAYER); , слоем boardLayeredPane по умолчанию была доска.

5. @Abra Я проверю это, спасибо!