如何将按钮拖放到GridPane上? [英] How to drag and drop button onto GridPane?
问题描述
我正在一个学校项目上创建一个简单的战舰游戏,我想使用拖放功能将按钮从屏幕底部的HBox拖动到玩家用来放置船只的GridPane。但我无法使其正常工作。这是现在我的董事会图片。
I'm working on a school project creating a simple battleship game and i want to use the Drag And Drop function to drag buttons from HBox on the bottom of the screen to the GridPane that the player uses to place ships on. But i can't get it to work properly. Here's a picture of my board per now.
我尝试使用button.setOnMouseDragged(e-> {CODE HERE});
I have tried to use the button.setOnMouseDragged(e -> {CODE HERE}); but it doesnt work.
public class GridOrganizer {
private BorderPane borderPane;
public GridOrganizer() {
borderPane = new BorderPane();
borderPane.setStyle("-fx-background-color: grey;");
borderPane.setPrefHeight(600);
borderPane.setPrefWidth(600);
createGrid();
}
public void createGrid() {
//Creates the grids where the game is played and buttons/ships to place on grid
GridPane playerGrid = new GridPane();
GridPane enemyGrid = new GridPane();
Insets padding = new Insets(10);
//Create playergrid
for (int i = 0; i < 10; i++) {
playerGrid.getColumnConstraints().add(new ColumnConstraints(50)); //50 wide
playerGrid.getRowConstraints().add(new RowConstraints(50));
}
//Create enemygrid
for (int i = 0; i < 10; i++) {
enemyGrid.getColumnConstraints().add(new ColumnConstraints(50)); //50 wide
enemyGrid.getRowConstraints().add(new RowConstraints(50));
}
//looping through row and columns and adds buttons
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
Button button = new Button();
button.setPrefHeight(50);
button.setPrefWidth(50);
GridPane.setConstraints(button, j, i); //(button, column, row)
playerGrid.getChildren().add(button); //add button on each index
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
//HIT or MISS
System.out.println("Row: " + GridPane.getRowIndex(button) + ", Column: " + GridPane.getColumnIndex(button));
button.setStyle("-fx-background-color: grey;");
}
});
}
}
//..same with enemy grid
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
Button button = new Button();
button.setPrefHeight(50);
button.setPrefWidth(50);
GridPane.setConstraints(button, j, i); //(button, column, row)
enemyGrid.getChildren().add(button); //add button on each index
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
System.out.println("Row: " + GridPane.getRowIndex(button) + ", Column: " + GridPane.getColumnIndex(button));
button.setStyle("-fx-background-color: grey;");
}
});
}
}
//Make buttons for the ships
Button rowboat = new Button("Rowboat");
Button sailboat = new Button("Sailboat");
Button submarine = new Button("Submarine");
Button destroyer = new Button("Destroyer");
Button battleship = new Button("Battleship");
//Size the ship buttons to match game description
battleship.setPrefHeight(50);
battleship.setPrefWidth(250); //size 5
destroyer.setPrefHeight(50);
destroyer.setPrefWidth(200); //size 4
submarine.setPrefHeight(50);
submarine.setPrefWidth(150); //size 3
sailboat.setPrefHeight(50);
sailboat.setPrefWidth(150); //size 3
rowboat.setPrefHeight(50);
rowboat.setPrefWidth(100); //size 2
//Drags button
rowboat.setOnMouseDragged(e -> {
//CODE HERE
});
//Drops button on grid
//CODE HERE
sailboat.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
submarine.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
destroyer.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
battleship.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
//PLACE SHIP
}
});
HBox ships = new HBox(); //Horizontal box
ships.getChildren().addAll(rowboat, sailboat, submarine, destroyer, battleship); //Add buttons to horizontal box
//Add grids and ship buttons to pane with padding
borderPane.setLeft(enemyGrid);
BorderPane.setMargin(enemyGrid, padding);
borderPane.setRight(playerGrid);
BorderPane.setMargin(playerGrid, padding);
borderPane.setBottom(ships);
BorderPane.setMargin(ships, padding);
}
public Pane getGrid() {
return borderPane;
}
}
推荐答案
此处的计划是使用拖动事件结束时创建按钮所需的数据来启动拖动事件。在您的代码中,看起来您已经将 Buttons
添加到 Grid
中。这意味着您只需要传输 String
即可更改 Button的
文本。在我的代码中,创建 Grid
时,我使用的是 StackPane
。然后,我创建并添加 Buttons
。您的方法可能更好。我已经看了那么远。我添加了MCVE(来自此处的更改的代码):
The plan here is to start a drag event with the data needed to create your button when the drag event finished. In your code, it looks like you have added the Buttons
into the Grid
already. That means you need to only transfer a String
to change the Button's
text. In my code, I am using a StackPane
when creating the Grid
. I then create and add the Buttons
later. You approach may be better. I have looked that far. I have added an MCVE (Altered code from here):
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Demonstrates a drag-and-drop feature.
*/
public class HelloDragAndDrop extends Application
{
@Override
public void start(Stage stage)
{
//Source Buttons.
final Button boat1 = new Button("boat1");
final Button boat2 = new Button("boat2");
final Button boat3 = new Button("boat3");
final Button boat4 = new Button("boat4");
//Adding OnDragDetected to source Buttons.
setOnDragDetected(boat1);
setOnDragDetected(boat2);
setOnDragDetected(boat3);
setOnDragDetected(boat4);
//Adding onDragDone to source Buttons.
setOnDragDone(boat1);
setOnDragDone(boat2);
setOnDragDone(boat3);
setOnDragDone(boat4);
//Creating GridPane
GridPane gridPane = new GridPane();
gridPane.setVgap(5);
gridPane.setHgap(5);
gridPane.setPadding(new Insets(5, 5, 5, 5));
gridPane.setStyle("-fx-background-color: black;");
//Adding StackPane to every Cell in the GridPane and Adding the Target Events to each StackPane.
for (int i = 0; i < 6; i++) {
StackPane stackPane = new StackPane();
stackPane.setPrefSize(150, 50);
stackPane.setStyle("-fx-background-color: yellow;");
setOnDragOver(stackPane);
setOnDragEntered(stackPane);
setOnDragExited(stackPane);
setOnDragDropped(stackPane);
gridPane.add(stackPane, i / 3, i % 3);
}
HBox root = new HBox(new VBox(boat1, boat2, boat3, boat4), gridPane);
stage.setTitle("Hello Drag And Drop");
Scene scene = new Scene(root, 400, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
Application.launch(args);
}
//source events handlers
public void setOnDragDetected(Button source)
{
source.setOnDragDetected((MouseEvent event) -> {
/* drag was detected, start drag-and-drop gesture*/
System.out.println("onDragDetected");
/* allow any transfer mode */
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
/* put a string on dragboard */
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
event.consume();
});
}
public void setOnDragDone(Button source)
{
source.setOnDragDone((DragEvent event) -> {
/* the drag-and-drop gesture ended */
System.out.println("onDragDone");
/* if the data was successfully moved, clear it */
// if (event.getTransferMode() == TransferMode.MOVE) {
// source.setText("");
// }
event.consume();
});
}
//target event handlers
public void setOnDragOver(StackPane target)
{
target.setOnDragOver((DragEvent event) -> {
/* data is dragged over the target */
System.out.println("onDragOver");
/* accept it only if it is not dragged from the same node
* and if it has a string data */
if (event.getGestureSource() != target
&& event.getDragboard().hasString()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
});
}
public void setOnDragEntered(StackPane target)
{
target.setOnDragEntered((DragEvent event) -> {
/* the drag-and-drop gesture entered the target */
System.out.println("onDragEntered");
/* show to the user that it is an actual gesture target */
if (event.getGestureSource() != target
&& event.getDragboard().hasString()) {
target.setStyle("-fx-background-color: green;");
}
event.consume();
});
}
public void setOnDragExited(StackPane target)
{
target.setOnDragExited((DragEvent event) -> {
/* mouse moved away, remove the graphical cues */
target.setStyle("-fx-background-color: transparent;");
event.consume();
});
}
public void setOnDragDropped(StackPane target)
{
target.setOnDragDropped((DragEvent event) -> {
/* data dropped */
System.out.println("onDragDropped");
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
//target.setText(db.getString());
Button tempBoat = new Button(db.getString());
tempBoat.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
target.getChildren().clear();
target.getChildren().add(tempBoat);
success = true;
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
});
}
}
在此代码中,代表
均具有 Boats
的按钮 onDragDetected
和 onDragDone
附加了事件处理程序。它们被视为源
/拖动事件的开始。对于 GridPane
中的每个单元格,都会添加一个 StackPane
。这些 StackPanes
被视为 Target
/拖放事件的区域。每个 StackPane
具有 onDragOver
, onDragEntered
, onDragDropped
和 onDragExited
附加。拖动事件完成后,接收事件的 StackPane
/ Target
会得到一个新的作为孩子的Button
与 Source
Button
的名字相同。
In this code, the Buttons
that represent the Boats
all have onDragDetected
and onDragDone
event handlers attached. They are considered Source
/start of a Drag event. For every cell in the GridPane
, a StackPane
is added. These StackPanes
are considered the Target
/areas to drop drag events. Each StackPane
has onDragOver
, onDragEntered
, onDragDropped
, and onDragExited
attached. Once a drag event is complete, the StackPane
/Target
that receives the event gets a new Button
as a child with the same name as the Source
Button
.
这篇关于如何将按钮拖放到GridPane上?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!