4 votes

Plusieurs composants dans une colonne de TableView JavaFX

Je travaille avec JavaFx 2.2. J'ai un problème pour placer différents composants dans une colonne TableView. Par exemple, j'ai deux colonnes

1) Réponse

2) Type de réponse

Si le Type de réponse contient "Choix Multiple", alors la cellule correspondante dans la colonne Réponse doit afficher une ComboBox sinon elle doit afficher un TextField.

Voici un exemple de code ci-dessous mais il affiche soit une ComboBox soit un TextField mais pas les deux dans des cellules différentes de la même colonne.

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.scene.control.cell.ComboBoxTableCell;

public class TableCellWithMultipleComponent extends Application {

     @SuppressWarnings("rawtypes")
TableColumn answerTypeCol; 
@SuppressWarnings("rawtypes")
TableColumn answerCol; 
ObservableList namesChoiceList;

public static void main(String[] args) {
    launch(args);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void start(final Stage primaryStage) {
    primaryStage.setTitle("Table Cell With Multiple Components");

     TableView table = new TableView();
     table.setEditable(true);
      final ObservableList data = 
                FXCollections.observableArrayList(
                    new Person("A", "Choix Multiple"),
                    new Person("JOHN", "Texte Libre"),
                    new Person("123", "Texte Libre"),
                    new Person("D", "Choix Multiple")
                );

    GridPane gridpane = new GridPane();
    gridpane.setPadding(new Insets(5));
    gridpane.setHgap(5);
    gridpane.setVgap(5);

    namesChoiceList = FXCollections.observableArrayList("A", "B", "C", "D", "REPONSE_INVALIDE", "PAS_DE_REPONSE");

    answerCol = new TableColumn();
    answerCol.setText("Réponses");
    answerCol.setMinWidth(210);
    answerCol.setEditable(true);
    answerCol.setCellValueFactory(new PropertyValueFactory("answers"));

    answerCol.setCellFactory( new Callback, TableCell>() {
        @Override
        public TableCell call(TableColumn arg0) {
            return new anyMethod();
        }
    });

    answerTypeCol = new TableColumn();
    answerTypeCol.setText("Type de réponse");
    answerTypeCol.setMinWidth(210);
    answerTypeCol.setEditable(true);
    answerTypeCol.setCellValueFactory(new PropertyValueFactory("answersType"));

    table.setItems(data);
    table.getColumns().addAll(answerCol, answerTypeCol);

    StackPane root = new StackPane();

    Scene scene =new Scene(root, 500, 550);

    gridpane.add(table, 1, 5,1,20 );

    root.getChildren().addAll(gridpane);
    primaryStage.setScene(scene);
    primaryStage.show();

   }

  private class anyMethod extends TableCell {

    @SuppressWarnings("unchecked")
    @Override
    protected void updateItem(String item, boolean arg1) {
        super.updateItem(item, arg1);

        answerCol.setCellFactory(ComboBoxTableCell.forTableColumn(namesChoiceList));

        /****  Je dois exécuter ce code commenté pour que si la cellule de la colonne contient le texte "Choix Multiple", alors
         * il affiche la comboBox sinon il affiche le champ de texte dans la cellule du TableView

        if (item.equalsIgnoreCase("Choix Multiple")){
            answerCol.setCellFactory(ComboBoxTableCell.forTableColumn(namesChoiceList));
        }
        else{
            //answerCol.setCellFactory(TextFieldTableCell.forTableColumn());
        }
    ****/
    }

}

public static class Person {
    private final SimpleStringProperty answers;
    private final SimpleStringProperty answersType;

    private Person(String answers, String answersType) {
        this.answers = new SimpleStringProperty(answers);
        this.answersType = new SimpleStringProperty(answersType);
    }

    public String getAnswers() {
        return answers.get();
    }
    public void setAnswers(String answers) {
        this.answers.set(answers);
    }

    public String getAnswersType() {
        return answersType.get();
    }
    public void setAnswersType(String answersType) {
        this.answersType.set(answersType);
    }
   }

}

5voto

jewelsea Points 40435

Voici un exemple d'une EditingCell qui rend un contrôle différent dans la cellule (champ Texte ou Case à cocher) en fonction du type de donnée représenté par le champ de sauvegarde de la cellule (String ou Boolean). Le code exécutable complet est disponible en tant que gist.

Pour votre exemple particulier, utilisez le même concept sauf que vous interrogez le type pour soit une String => Champ de texte ou ObservableList => combobox. De plus, pour votre exemple particulier, ChoiceBox peut être un contrôle plus simple à utiliser que ComboBox.

class EditingCell extends TableCell {
private TextField textField;
private CheckBox checkBox;
public EditingCell() {}

@Override public void startEdit() {
  if (!isEmpty()) {
    super.startEdit();

    if (getItem() instanceof Boolean) {
      createCheckBox();
      setText(null);
      setGraphic(checkBox);
    } else {
      createTextField();
      setText(null);
      setGraphic(textField);
      textField.selectAll();
    }  
  }
}

@Override public void cancelEdit() {
  super.cancelEdit();

  if (getItem() instanceof Boolean) {
    setText(getItem().toString());
  } else {
    setText((String) getItem());
  }  
  setGraphic(null);
}

@Override public void updateItem(Object item, boolean empty) {
  super.updateItem(item, empty);

  if (empty) {
    setText(null);
    setGraphic(null);
  } else {
    if (isEditing()) {
      if (getItem() instanceof Boolean) {
        if (checkBox != null) {
          checkBox.setSelected(getBoolean());
        }
        setText(null);
        setGraphic(checkBox);
      } else {
        if (textField != null) {
          textField.setText(getString());
        }
        setText(null);
        setGraphic(textField);
      }  
    } else {
      setText(getString());
      setGraphic(null);
    }
  }
}

private void createTextField() {
  textField = new TextField(getString());
  textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
  textField.focusedProperty().addListener(new ChangeListener() {
    @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) {
      if (!newValue) {
        commitEdit(textField.getText());
      }
    }
  });
}

private void createCheckBox() {
  checkBox = new CheckBox();
  checkBox.setSelected(getBoolean());
  checkBox.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
  checkBox.focusedProperty().addListener(new ChangeListener() {
    @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) {
      if (!newValue) {
        commitEdit(checkBox.isSelected());
      }
    }
  });
}

private String getString() {
  return getItem() == null ? "" : getItem().toString();
}

private Boolean getBoolean() {
  return getItem() == null ? false : (Boolean) getItem();
}
}

3voto

user1414600 Points 85

Voici le code de travail pour ma question. Merci jewelsea

    import javafx.application.Application;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.ComboBox;
    import javafx.scene.control.TableCell;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextField;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.Callback;

    public class TableCellWithMultipleComponent extends Application {
        @SuppressWarnings("rawtypes")
        TableColumn answerTypeCol; 
        @SuppressWarnings("rawtypes")
        TableColumn answerCol; 
        ObservableList namesChoiceList;
        @SuppressWarnings("rawtypes")
        ComboBox comboBox;
        TextField textField;

        public static void main(String[] args) {
            launch(args);
        }

        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Override
        public void start(final Stage primaryStage) {
            primaryStage.setTitle("Table Cell With Multiple Components");

             TableView table = new TableView();
             table.setEditable(true);
              final ObservableList data = 
                        FXCollections.observableArrayList(
                            new Person("A", "Choix multiple"),
                            new Person("JOHN", "Texte libre"),
                            new Person("123", "Texte libre"),
                            new Person("D", "Choix multiple")
                        );

            GridPane gridpane = new GridPane();
            gridpane.setPadding(new Insets(5));
            gridpane.setHgap(5);
            gridpane.setVgap(5);

            namesChoiceList = FXCollections.observableArrayList("A", "B", "C", "D", "REPONSE_INVALIDE", "PAS_DE_REPONSE");

            answerCol = new TableColumn();
            answerCol.setText("Réponses");
            answerCol.setMinWidth(210);
            answerCol.setEditable(true);
            answerCol.setCellValueFactory(new PropertyValueFactory("answers"));

            answerCol.setCellFactory( new Callback, TableCell>() {
                @Override
                public TableCell call(TableColumn arg0) {
                    return new anyMethod();
                }
            });

            answerTypeCol = new TableColumn();
            answerTypeCol.setText("Type de réponse");
            answerTypeCol.setMinWidth(210);
            answerTypeCol.setEditable(true);
            answerTypeCol.setCellValueFactory(new PropertyValueFactory("answersType"));

            table.setItems(data);
            table.getColumns().addAll(answerCol, answerTypeCol);

            StackPane root = new StackPane();

            Scene scene =new Scene(root, 500, 550);

            gridpane.add(table, 1, 5,1,20 );

            root.getChildren().addAll(gridpane);
            primaryStage.setScene(scene);
            primaryStage.show();

       }

        private class anyMethod extends TableCell {

            @SuppressWarnings({ "unchecked", "rawtypes" })
            public anyMethod(){

                comboBox = new ComboBox();
                textField = new TextField();
                comboBox.setItems(namesChoiceList);
            }

            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                     if (empty) {
                    setText(null);
                   setGraphic(null);
                    System.out.println("Vide");
                 } else {
                    if( getTableView().getColumns().get(1).getCellData(getIndex()).toString().startsWith("M")){

                     System.out.println("Création ComboBox");
                     setGraphic(comboBox);
                    }
                    else{
                        setGraphic(textField);
                    }
                 }

            }

        }

        public static class Person {
            private final SimpleStringProperty answers;
            private final SimpleStringProperty answersType;

            private Person(String answers, String answersType) {
                this.answers = new SimpleStringProperty(answers);
                this.answersType = new SimpleStringProperty(answersType);
            }

            public String getAnswers() {
                return answers.get();
            }
            public void setAnswers(String answers) {
                this.answers.set(answers);
            }

            public String getAnswersType() {
                return answersType.get();
            }
            public void setAnswersType(String answersType) {
                this.answersType.set(answersType);
            }
        }

    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X