#java #swing #drag-and-drop #jlayeredpane
#java #качать #перетаскивание #jlayeredpane
Вопрос:
Я пытаюсь внедрить операцию перетаскивания в свою программу; Я нашел следующий пример, который иллюстрирует многое из того, что я пытаюсь сделать:
package sandbox;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
/**
* Example showing the use of a JLayeredPane to implement dragging an object
* across a JPanel containing other objects.
* <P>
* Basic idea: Create a JLayeredPane as a container, then put the JPanel containing
* the application's components or whatever in the JLayeredPane.DEFAULT_LAYER layer of that layered pane.
* The code is going to drag a JComponent object by calling JComponent.setPosition(x,y)
* on the component. When a mouse is clicked on the panel to start the dragging, put the
* component on the drag layer of the layered pane; as it is dragged, continue to call
* setPosition to move it. When the mouse is released, use the x.y position of the release
* to decide what to do with it next.
*
*/
public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener
{
private static final long serialVersionUID = 1L;
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
public ChessBoard()
{
Dimension boardSize = new Dimension(600, 600);
// Use a Layered Pane for this application
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize( boardSize );
layeredPane.addMouseListener( this );
layeredPane.addMouseMotionListener( this );
getContentPane().add(layeredPane);
//debug
LayoutManager lm = layeredPane.getLayout();
System.out.println("Layered pane layout name is " (lm == null? "<null>" : lm.getClass().getName()));
// Add a chess board to the Layered Pane on the DEFAULT layer
chessBoard = new JPanel();
chessBoard.setLayout( new GridLayout(8, 8) );
chessBoard.setPreferredSize( boardSize );
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
// Build the Chess Board squares
// We use an 8x8 grid, and put a JPanel with BorderLayout on each square.
for (int i = 0; i < 8; i )
{
for (int j = 0; j < 8; j )
{
JPanel square = new JPanel( new BorderLayout() );
square.setBackground( (i j) % 2 == 0 ? Color.gray : Color.white );
chessBoard.add( square );
}
}
// Add a few pieces to the board
// we do this with an ImageIcon that gets added to the square's panel.
ImageIcon duke = new ImageIcon("granary.gif"); // this is the image to add to each space.
addDuke(duke, 0);
addDuke(duke, 6);
addDuke(duke, 15);
addDuke(duke, 20);
}
private void addDuke(ImageIcon duke, int boardPosition)
{
JLabel pieceLabel = new JLabel(duke);
JPanel piecePanel = (JPanel)chessBoard.getComponent(boardPosition);
piecePanel.add(pieceLabel);
}
/*
** Add the selected chess piece to the dragging layer so it can be moved
*/
public void mousePressed(MouseEvent e)
{
// get the component where the user pressed; iff that's not a panel,
// we'll put it on the dragging layer.
chessPiece = null; // change1 swap the change1 lines
// chessPiece = new JLabel(new ImageIcon("house1x1.gif")); // change1
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
if (c instanceof JPanel) return;
// get the location of the panel containing the image panel, i.e.,
// the square's panel. we adjust the location to which we move the
// piece by this amount so the piece doesn't 'snap to' the cursor
// location.
Point parentLocation = c.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
chessPiece = (JLabel)c; // change2 - comment out
chessPiece.setLocation(e.getX() xAdjustment, e.getY() yAdjustment);
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER); // evidently this removes it from the default layer also.
layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
/*
** Move the chess piece around
*/
public void mouseDragged(MouseEvent me)
{
if (chessPiece == null) return;
// The drag location should be within the bounds of the chess board
int x = me.getX() xAdjustment;
int xMax = layeredPane.getWidth() - chessPiece.getWidth();
x = Math.min(x, xMax);
x = Math.max(x, 0);
int y = me.getY() yAdjustment;
int yMax = layeredPane.getHeight() - chessPiece.getHeight();
y = Math.min(y, yMax);
y = Math.max(y, 0);
chessPiece.setLocation(x, y); // evidently this works for whatever layer contains the piece.
// also, the layout manager of its new home is evidently not the same as lower layers.
}
/*
** Drop the chess piece back onto the chess board
*/
public void mouseReleased(MouseEvent e)
{
layeredPane.setCursor(null);
if (chessPiece == null) return;
// Make sure the chess piece is no longer painted on the layered pane
chessPiece.setVisible(false);
layeredPane.remove(chessPiece);
chessPiece.setVisible(true);
// The drop location should be within the bounds of the chess board
int xMax = layeredPane.getWidth() - chessPiece.getWidth();
int x = Math.min(e.getX(), xMax);
x = Math.max(x, 0);
int yMax = layeredPane.getHeight() - chessPiece.getHeight();
int y = Math.min(e.getY(), yMax);
y = Math.max(y, 0);
Component c = chessBoard.findComponentAt(x, y);
Container parent = null;
if (c instanceof JLabel)
{
parent = c.getParent(); // there's a piece on the square already; remove it from the panel.
parent.remove(0);
}
else
{
parent = (Container)c;
}
parent.add( chessPiece ); // this adds the piece back to the default layer
parent.validate();
}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public static void main(String[] args)
{
JFrame frame = new ChessBoard();
frame.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
frame.setResizable( false );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
Это делает работу для случая шахматной доски, а именно позволяет пользователю перетаскивать любые фигуры на шахматной доске на другую клетку.
В приложении, которое я пишу, перетаскиваемый элемент не существует, пока пользователь не нажмет на что-то, что запускает операцию перетаскивания. У меня возникли проблемы с выяснением, как сделать это создание и показать его.
Моя текущая попытка касается строк, помеченных как ‘change1’ и ‘change2’; вы меняете местами две строки на ‘change1’ и закомментируете одну с помощью ‘change2’. Другими словами, создайте JLabel при нажатии мыши и (надеюсь) перетащите его. Но когда я запускаю это, изображение не отображается при нажатии или во время перетаскивания, но отображается на квадрате в конце перетаскивания.
Что я здесь пропустил? Я немного смущен JLayeredPane, javadoc говорит, что он будет следовать правилам компоновки, но не будут ли правила компоновки применяться ко всем компонентам на всех слоях, или только к нижней части, или ко всем слоям, но отдельно, что? Я бы не подумал, что это проблема с макетом, но я не знаю, что не так. Нужно ли мне где-то какое-то обновление пользовательского интерфейса? Я думал, что добавление компонента приведет к аннулированию панели.
Ответ №1:
Исходный код был написан в предположении, что вы нажимаете на шахматную фигуру.
Теперь вы хотите щелкнуть по пустой ячейке, что потребует следующих изменений.
- Шахматная доска состоит из JPanels в каждой ячейке. Некоторые ячейки будут содержать JLabel, представляющий шахматную фигуру. Текущая логика в событии mousePressed ожидает, что вы нажмете на JLabel, иначе некоторая обработка будет пропущена.
Вам нужно удалить:
//if (c instanceof JPanel) return;
- По умолчанию компонент Swing имеет размер 0 при его создании.
Вам нужно задать ему размер:
chessPiece.setSize( chessPiece.getPreferredSize() );
- Логика позиционирования метки основана на нахождении местоположения выбранного компонента относительно родительского. Поскольку метки нет, эта логика теперь основана на панели относительно многоуровневой панели.
Вам нужно настроить эту логику, чтобы снова сделать ее относительной к родительской панели:
//Point parentLocation = c.getParent().getLocation();
Point parentLocation = c.getLocation();
Мой обновленный метод с нажатой мышью выглядит следующим образом:
public void mousePressed(MouseEvent e)
{
// get the component where the user pressed; iff that's not a panel,
// we'll put it on the dragging layer.
//chessPiece = null; // change1 swap the change1 lines
chessPiece = new JLabel(new ImageIcon("dukewavered.gif")); // change1
chessPiece.setSize( chessPiece.getPreferredSize() );
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
//if (c instanceof JPanel) return;
// get the location of the panel containing the image panel, i.e.,
// the square's panel. we adjust the location to which we move the
// piece by this amount so the piece doesn't 'snap to' the cursor
// location.
//Point parentLocation = c.getParent().getLocation();
Point parentLocation = c.getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
//chessPiece = (JLabel)c; // change2 - comment out
chessPiece.setLocation(e.getX() xAdjustment, e.getY() yAdjustment);
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER); // evidently this removes it from the default layer also.
layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
Обратите внимание, что вышеуказанные изменения нарушат старую функциональность, позволяющую перетаскивать существующую метку. Если вам нужна функциональность для обоих, то ваша логика будет определяться тем, нажимаете ли вы на JLabel (в этом случае вы используете старую логику) или нажимаете на JPanel (в этом случае вы используете более новую логику).
Комментарии:
1. ОТЛИЧНЫЕ объяснения. Как оказалось, то, что я хотел, было проще, но поскольку вы объяснили, что стоит за изменениями в логике, которые, по вашему мнению, я хотел, я смог сделать что-то другое , поэтому я предпочитаю иметь объяснение, а не только пример.