4

I am trying out JFX Drag and Drop feature in my application (later connecting the objects in a sequence). I could not find any easy way to drag and drop my ImageView/Button at suitable position in my pane, hence I am planning to apply use of GridPane. The GridPane would be a large canvas with more than (50x50) cells.

If I specify in my code that I need to drag and drop by ImageView at, let's say, (2,2) cell, I am able to do it. But, I need to give that access to my user. User could move the pointer in grid and would drop the ImageView/Button at any cell in the grid.

Now, I would like to find out rowID and columnID of the cell on mouse entered in a particular cell of the GridPane.

I am handling mouse event in my Controller as follows:

package sample;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.*;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable{
Stage stage;

@FXML
private GridPane gridPane;

public void setStage(Stage primaryStage){
    stage = primaryStage;
}

@Override
public void initialize(URL location, ResourceBundle resources) {
    System.out.println("initialize");
}


@FXML
private void handleMouseEntered(MouseEvent event){
    System.out.println("MouseEntered");
}

}

When enters in the gridpane, I get "MouseEntered" only once. Besides, I am not able to get any RowID and ColumnID, hence, I have not written any function in the function.

My interface looks like following: enter image description here

I would like to know two things:

[] How to detect mouse entry in each cell of the gridpane?

[] How to find out row and column IDs of the particular cell?

Thanks in advance.

Sujit Devkar
  • 1,195
  • 3
  • 12
  • 22
  • Register the mouse listeners with the nodes in each cell. Then you know which cell was entered. – James_D Jun 28 '15 at 05:15
  • Have a look at this answer: http://stackoverflow.com/questions/28030378/javafx-how-move-objects-through-tilepane/28039693#28039693 It partly covers your question. Combined with @James_D suggestion it should work. – eckig Jun 28 '15 at 08:04
  • @James_D The method you suggested works! But, I would have a large (50x50 or more) sized grid. Here, the method may not be optimal. Could you please suggest any suitable method for it? Thanks. – Sujit Devkar Jun 29 '15 at 04:35
  • I don't understand why doing the same with 2500 cells would be an issue. What went wrong when you tried it? – James_D Jun 29 '15 at 04:54
  • @James_D Hi. The suggested methods works fine. But, I had to add Panes for each cell separately. While creating the grid in SceneBuilder did not take much time. Hence, I was thinking of removing the manual work on adding 2500 panes. Could you please suggest how to overcome this? Thanks. – Sujit Devkar Jun 29 '15 at 05:03
  • Then just define the panes in the controller. See update. – James_D Jun 29 '15 at 11:49

1 Answers1

9

You can get the values by calling GridPane.getColumnIndex(node) and GridPane.getRowIndex(node).

You haven't shown what you're putting in the grid pane, and even whether you are populating it in FXML or in Java, but here's some basic functionality. Here I (tediously) populate the GridPane in FXML, it might be better to populate it in Java (i.e. in the controller), depending on your use case. (That way, the handler gets a bit cleaner too.)

Controller class:

import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;


public class GridPaneTrackingController {

    @FXML
    private void mouseEntered(MouseEvent e) {
        Node source = (Node)e.getSource() ;
        Integer colIndex = GridPane.getColumnIndex(source);
        Integer rowIndex = GridPane.getRowIndex(source);
        System.out.printf("Mouse entered cell [%d, %d]%n", colIndex.intValue(), rowIndex.intValue());
    }
}

If you don't want to define the contents of the cells in FXML, then you can just define them in the controller. That makes things cleaner, as you can just register the listener when you define them:

import javafx.fxml.FXML;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;


public class GridPaneTrackingController {

    @FXML
    private GridPane grid ;

    public void initialize() {
        int numCols = 4 ;
        int numRows = 4 ;

        for (int i = 0 ; i < numCols ; i++) {
            ColumnConstraints colConstraints = new ColumnConstraints();
            colConstraints.setHgrow(Priority.SOMETIMES);
            grid.getColumnConstraints().add(colConstraints);
        }

        for (int i = 0 ; i < numRows ; i++) {
            RowConstraints rowConstraints = new RowConstraints();
            rowConstraints.setVgrow(Priority.SOMETIMES);
            grid.getRowConstraints().add(rowConstraints);
        }

        for (int i = 0 ; i < numCols ; i++) {
            for (int j = 0; j < numRows; j++) {
                addPane(i, j);
            }
        }
    }

    private void addPane(int colIndex, int rowIndex) {
        Pane pane = new Pane();
        pane.setOnMouseEntered(e -> {
            System.out.printf("Mouse enetered cell [%d, %d]%n", colIndex, rowIndex);
        });
        grid.add(pane, colIndex, rowIndex);
    }

}

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.GridPane?>

<GridPane xmlns:fx="http://javafx.com/fxml/1" 
    fx:controller="GridPaneTrackingController" 
    fx:id="grid" gridLinesVisible="true">

</GridPane>

Application:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class GridPaneTrackingExample extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        GridPane root = FXMLLoader.load(getClass().getResource("GridPaneTrackingExample.fxml"));
        primaryStage.setScene(new Scene(root, 800, 800));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • This solved my problem. Now I have another problem related to handling events related to MouseEvent and DragEvent for which I will put another question. :) – Sujit Devkar Jun 29 '15 at 12:20
  • @James_D how can i populate the gridPane with content from database? – Israel Meshileya Aug 06 '17 at 22:12
  • 3
    @IsraelMeshileya What on earth does that have to do with this question? – James_D Aug 06 '17 at 22:23
  • @James_D I am sorry for that, I am having an issue on using database to populate the GridPane, wouldnt mind, if you can put me through in the cause of its implementation. – Israel Meshileya Aug 06 '17 at 22:28
  • @IsraelMeshileya Don't hijack other questions. If you have a question that isn't already answered, then post one. Make sure you thoroughly read the [help pages on asking questions](https://stackoverflow.com/help/asking) before you write your question, as well as [search](https://stackoverflow.com/help/searching) for similar questions. – James_D Aug 06 '17 at 22:32
  • @James_D , i have done that and was directed to https://stackoverflow.com/questions/45533247/how-to-use-javafx-gridpane-to-display-data-from-a-mysql-database . thanks so much as you help in checking it out. – Israel Meshileya Aug 06 '17 at 22:35