[英]How to get coordinates of click on resized ImageView in JavaFX Gridpane
[英]JavaFX: Update ImageView on GridPane click
我正在使用 JavaFX 開發掃雷游戲:
我的GridPane
由ImageViews
組成,我試圖找到一種方法來找出在GridPane
上單擊的圖像的列和行索引。 我目前有這段代碼:
gameGrid.setOnMouseClicked(event -> //gameGrid is my GridPane
{
Node source = (Node)event.getSource();
int columnIndex = GridPane.getColumnIndex(source);
System.out.println(columnIndex);
int rowIndex = GridPane.getRowIndex(source);
if(event.getButton()== MouseButton.PRIMARY)
game.newRevealCell(columnIndex,rowIndex);
else if(event.getButton()==MouseButton.SECONDARY)
game.getGrid()[columnIndex][rowIndex].setFlagged(true);
//game.getGrid is a 2D array containing the game cells
});
但是,方法getColumnIndex
和getRowIndex
返回null
。 我究竟做錯了什么?
從這個例子開始,下面的變體用Button
的N
x N
實例填充GridPane
,將每個實例添加到List<Button>
。 方法getGridButton()
顯示了如何根據其網格坐標有效地獲取按鈕引用,並且動作偵聽器顯示單擊和找到的按鈕是相同的。
每個網格按鈕如何知道自己在網格上的位置? 每個都有自己的匿名類實例——按鈕的事件處理程序——可以訪問傳遞給createGridButton()
的行和列參數。 這些參數實際上是最終的; 相比之下,使用早期版本的 Java 的原始示例必須明確地使參數成為最終參數。
雖然此方法獲取網格中任何Node
的行和列,但Button
或ToggleButton
在此上下文中可能更方便。 特別是,您可以將setGraphic()
與ContentDisplay.GRAPHIC_ONLY
結合使用以獲得所需的外觀。
順便說一句, GridPane
方法getColumnIndex
和getRowIndex
返回null
,因為它們引用子項的索引約束,僅當已設置時,如此處所示。
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
/** @see https://stackoverflow.com/a/69429741/230513 */
public class GridButtonTest extends Application {
private static final int N = 5;
private final List<Button> list = new ArrayList<>();
private Button getGridButton(int r, int c) {
int index = r * N + c;
return list.get(index);
}
private Button createGridButton(int row, int col) {
Button button = new Button("r" + row + ",c" + col);
button.setOnAction((ActionEvent event) -> {
System.out.println(event.getSource() == getGridButton(row, col));
});
return button;
}
@Override
public void start(Stage stage) {
stage.setTitle("GridButtonTest");
GridPane root = new GridPane();
for (int i = 0; i < N * N; i++) {
int row = i / N;
int col = i % N;
Button gb = createGridButton(row, col);
list.add(gb);
root.add(gb, col, row);
GridPane.setMargin(gb, new Insets(N));
}
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
對於使用二維數組的模型,還可以考慮List<List<Button>>
,如下所示:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
/** @see https://stackoverflow.com/a/69429741/230513 */
public class GridButtonTest extends Application {
private static final int N = 5;
private final List<List<Button>> list = new ArrayList<>();
private Button getGridButton(int r, int c) {
return list.get(r).get(c);
}
private Button createGridButton(int row, int col) {
Button button = new Button("r" + row + ",c" + col);
button.setOnAction((ActionEvent event) -> {
System.out.println(event.getSource() == getGridButton(row, col));
});
return button;
}
@Override
public void start(Stage stage) {
stage.setTitle("GridButtonTest");
GridPane root = new GridPane();
for (int row = 0; row < N; row++) {
list.add(new ArrayList<>());
for (int col = 0; col < N; col++) {
Button gb = createGridButton(row, col);
list.get(row).add(gb);
root.add(gb, col, row);
GridPane.setMargin(gb, new Insets(N));
}
}
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
+1 對於@trashgod 提供的所有評論和答案。
但試圖解決您的實際問題,我認為使用 event.getSource 是您問題的根本原因。 從事件返回的源將始終是 GridPane。
event.getTarget() 方法將為您提供您單擊的目標節點。 所以我認為將其更改為 getTarget() 將解決您的問題。
下面是我的意思的工作演示。
即使我沒有顯式設置索引約束,這也有效
。
更新:我誤認為顯式約束設置只能通過 GridPane.add 方法完成。 但是使用 add/addRow/addColumn 方法也會設置索引約束。
注意:如果您單擊的目標節點是 GridPane 的直接子節點(在您的情況下),這將起作用。 但是,如果您的目標節點不是 GridPane 的直接子節點,例如 StackPane 有一個標簽,並且如果您單擊該標簽,則會拋出空異常。
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class GridPaneIndexingDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
Scene scene = new Scene(root, 450, 450);
stage.setScene(scene);
stage.setTitle("GridPane");
stage.show();
GridPane grid = new GridPane();
grid.setGridLinesVisible(true);
grid.addRow(0, getPane(1), getPane(2), getPane(3));
grid.addRow(1, getPane(4), getPane(5), getPane(6));
grid.addRow(2, getPane(7), getPane(8), getPane(9));
grid.setOnMouseClicked(event -> {
Node source = (Node) event.getTarget();
int columnIndex = GridPane.getColumnIndex(source);
int rowIndex = GridPane.getRowIndex(source);
System.out.println("Row : " + rowIndex + ", Col : " + columnIndex);
});
root.getChildren().add(grid);
}
private StackPane getPane(int i) {
String[] colors = {"grey", "yellow", "blue", "pink", "brown", "white", "silver", "orange", "lightblue", "grey"};
StackPane pane = new StackPane();
pane.setPrefSize(150,150);
pane.setStyle("-fx-background-color:" + colors[i] + ";-fx-border-width:2px;");
return pane;
}
public static void main(String[] args) {
Application.launch(args);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.