How can I change a label that is on a gridpane in javafx

1

Good afternoon community,

Lately I've been exploring the javafx strand and creating an application for my masters degree. Briefly, the application receives an image of the user, and creates a gridpane over the image, depending on the number of columns and rows the user wants. Each gridpane cell has a value of 0.

The image is an example of the explanation:

So far so good. What I want and I can not do is add a mouse event, which whenever I click on a gridpane label / cell, the value 0 goes to 1.

package vistas;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ResourceBundle;

import javax.print.DocFlavor.URL;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.stage.FileChooser;
import principal.main;

public class AreaProjectoController {

    @FXML
    private Button meuBotaoImagem, meuBotaoGrelha, btnLimpaGrelha;

    @FXML
    private ImageView minhaImagem;

    @FXML
    private TextField txtGrelhaLeft, txtGrelhaRight;

    @FXML
    private AnchorPane painelGrelha, painelArea;

    @FXML
    private GridPane painelCriaGrelha;

    public void initialize(URL location, ResourceBundle resources) {}

    public void mostraImagem(ActionEvent evento) throws FileNotFoundException {

        FileChooser imagemEscolhida = new FileChooser();

        // Define a extensão do ficheiro
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("JPEG/PNG", "*.jpeg", "*.png");
        imagemEscolhida.getExtensionFilters().add(extFilter);

        // abre a janela para procurar uma imagem
        File ficheiro = imagemEscolhida.showOpenDialog(main.getPrimaryStage());

        // O if trata quando se cancela o carregamento de uma imagem
        if(ficheiro != null) {
            Image imagem = new Image(new FileInputStream(ficheiro));
            minhaImagem.setImage(imagem);
            painelGrelha.setVisible(true);
            txtGrelhaLeft.setText("0");
            txtGrelhaRight.setText("0");
        } 

    }

    public void criaGrelha(ActionEvent evento) {

        int txtLeft = 0, txtRight = 0, i = 1, ii = 1;

        ColumnConstraints colunas = null; 
        RowConstraints linhas = null;

        txtLeft = Integer.parseInt(txtGrelhaLeft.getText());
        txtRight = Integer.parseInt(txtGrelhaRight.getText());

        //Este for cria a grelha após receber os valores
        for(i = 1; i <= txtLeft; i++) {
            colunas = new ColumnConstraints();
            colunas.setPercentWidth(25);
            painelCriaGrelha.getColumnConstraints().add(colunas);
        }

        for(ii = 1; ii <= txtRight; ii++) {
            linhas = new RowConstraints();
            linhas.setPercentHeight(25);
            painelCriaGrelha.getRowConstraints().add(linhas);
        }

        Label fillLabel[][] = new Label[txtLeft][txtRight];

        for (int l = 0; l < fillLabel.length; l++) {
            for (int j = 0; j < fillLabel[l].length; j++) {
                fillLabel[l][j] = new Label();
                fillLabel[l][j].setText("0");
                painelCriaGrelha.add(fillLabel[l][j], l, j);
            }
        }

        painelCriaGrelha.setGridLinesVisible(true); //isto faz aparecer as linhas da grelha a preto
        painelArea.setVisible(true);

        System.out.println(fillLabel[2][2]);
    }

    public void limpaGrelha(ActionEvent evento) {

        painelCriaGrelha.getColumnConstraints().clear();
        painelCriaGrelha.getRowConstraints().clear();
        txtGrelhaLeft.setText("0");
        txtGrelhaRight.setText("0");

    }


}

This is the code that has the features we see in the image. It is the view controller class. Why my goal is to select the labels / cells that correspond to the blue area of the image. Note that the values go to an array. In this example the array is:

0000000000

0000000000

0000000000

0000000000

0000000000

0000000000

0000000000

0000000000

0000000000

0000000000

But it should be, after implementing the mouse click event, something like this:

0000111111

1111111111

1111111111

1111100011

1111100011

0000000000

0000000000

0000000000

0000000000

0000000000

Thank you.

    
asked by anonymous 18.09.2017 / 16:13

1 answer

0

I researched a lot about your problem and the solutions I found involved navigating all the nodes of the grid and putting an onMouseClick on all nodes (well pig in my opinion). As I have not found what seems most correct for your case I did a workaround that can solve your problem (or at least a good direction).

@FXML
private GridPane grid;

private ObservableList<ColumnConstraints> columns;
private ObservableList<RowConstraints> rows;


@Override
public void initialize(URL url, ResourceBundle rb) {
    grid.setGridLinesVisible(true);
    columns = grid.getColumnConstraints();
    rows = grid.getRowConstraints();
}

@FXML
public void mudarValorCelula(MouseEvent e){
    Double x, y, columnAcc = 0.0, rowAcc = 0.0;
    int i = 0, j = 0;

    // Pega a posição clicada pelo mouse
    x = e.getX();
    y = e.getY();

    // Calcula em qual coluna o X está
    for (ColumnConstraints c : columns){
        if(columnAcc < x && x < columnAcc + c.getPrefWidth()){
            break;
        }
        j++;
        columnAcc += c.getPrefWidth();           
    }

    // Calcula em qual linha o Y está
    for (RowConstraints c : rows){
        if(rowAcc < y && y < rowAcc + c.getPrefHeight()){
            break;
        }
        i++;
        rowAcc += c.getPrefHeight();           
    }

    // Modificando o elemento correto
    Label l = (Label) grid.getChildren().get(j*columns.size() + i);
    l.setText("1");
}

It is also necessary to put the changeValueCell method in the onMouseClick of your grid:

<GridPane fx:id="grid" layoutX="15.0" layoutY="55.0" onMouseClicked="#mudarValorCelula">

This solution assumes some important things:

  • Your grid is fully populated with Labels
  • Labels are in column order (see image below)
  • All rows and columns should have their constraint
  • This happens because the add method of the grid is thus grid.add(column, row) which is the opposite of what we are accustomed to, so we have to put the labels in that order:

    Ifyouwanttotakearow,youwillhavetostaylikethis(0,0)(1,0)(2,0)(0,1)...andchangethei*columns.size()+j

    Note:Ithasonlybeentestedwithsquarearrays,itdoesnotworkforothertypes.

    Obs2.:Ifyouknowthenumberofcolumnstheprioiisgoodtoputinplaceofcolumns.size()

    Theresultwasasfollows:

        
    19.09.2017 / 01:42