Edit the values of the TableView from TextField

2019-08-30 07:05发布

Hi I am trying in the spirit of the example in http://code.makery.ch/java/javafx-2-tutorial-intro/ to make a similar application where the TableView values can be edited by a series of TextFields instead of a popup form. The reason why I would wannt do it like that is that I am having many fields in a similar application I want to develop and I would like to avoid the user editing them on the TableView

The TableView shows a list of Persons where for each I record name, surname and country. I have tried to create a bidirectionalBinding between the name property of the Person bean and the textProperty() of the TextField but this doesn't work.

I also tried to add to the textProperty a ChangeListener so when it changes to update the ObservableList of propoerties and this also didn't work

Apparently I am doing something wrong and so far I have the following code:

FXDocumentController.java

    public class FXMLDocumentController implements Initializable {
    private static final Logger logger = Logger.getLogger(FXMLDocumentController.class.getName());
private ObservableList<Person> data;
    @FXML
    private TableView<Person> tableview;
    @FXML
    private TableColumn<Person, String> colName;
    @FXML
    private TableColumn<Person, String> colSurname;
    @FXML
    private TableColumn<Person, String> colCountry;
    @FXML
    private TextField name;
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        assert tableview != null : "fx:id=\"tableview\" was not injected: check your FXML file 'UserMaster.fxml'.";
     colName.setCellValueFactory(
        new PropertyValueFactory<Person,String>("name"));        
    colSurname.setCellValueFactory(                
        new PropertyValueFactory<Person,String>("surname"));
    colCountry.setCellValueFactory(
        new PropertyValueFactory<Person,String>("country"));       

    DBClass objDbClass = new DBClass();
    try{
        con = objDbClass.getConnection();
        buildData();
       tableview.setOnMouseClicked(new EventHandler<MouseEvent>() {
      @Override
        public void handle(MouseEvent mouseEvent) {
          if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
            if (mouseEvent.getClickCount() == 1) {
                Person p = tableview.getSelectionModel().getSelectedItem();
                //name.textProperty().setValue(p.getName());
                name.textProperty().bindBidirectional(p.name);
                //name.textProperty().bind(p.name);


          }
        }
      }
    });

       name.textProperty().addListener(new ChangeListener(){

            @Override
            public void changed(ObservableValue ov, Object t, Object t1) {
                System.out.println("Value changed!"); 
                /** Tried also this but this wont work
                name.textProperty().setValue((String)t1);
                int index = tableview.getSelectionModel().getSelectedIndex();
                data.get(index).name.setValue( (String) t1);
                tableview.setItems(data);
                * */
            }

                    }

               );
    }
    catch(ClassNotFoundException ce){
        logger.info(ce.toString());
    }
    catch(SQLException ce){
        logger.info(ce.toString());
    }
    }    //initialize



    private void buildData() {
            data = FXCollections.observableArrayList();
    try{ 
        data.add(new Person("Jon", "Doe", "USA"));
        data.add(new Person("Lars", "Andersson", "Sweden"));
        tableview.setItems(data);
    }
    catch(Exception e){
          e.printStackTrace();
          System.out.println("Error on Building Data");            
    }
    }

    }

Person.java

public class Person {
public SimpleStringProperty name = new SimpleStringProperty();
public SimpleStringProperty surname = new SimpleStringProperty();
public SimpleStringProperty country = new SimpleStringProperty();

public Person(String name, String surname, String country){
    this.name.set(name);
    this.surname.set(surname);
    this.country.set(country);
}

public String getName(){
    return name.get();
}

public String getSurname(){
    return surname.get();
}

public String getCountry(){
    return country.get();
}
}

And for the sake of completeness I am giving the fxml file (very ugly but I am experimenting with the functionality;)) and the launcher

FXMLDocument.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" blendMode="SRC_OVER" cache="false" disable="false" focusTraversable="false" prefHeight="576.0" prefWidth="1024.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="javafxdemoproject.FXMLDocumentController">
  <children>
    <SplitPane dividerPositions="0.3336594911937378" focusTraversable="true" layoutX="0.0" layoutY="55.0" prefHeight="521.0" prefWidth="1024.0">
      <items>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="410.0" prefWidth="297.0">
          <children>
            <TableView fx:id="tableview" editable="true" prefHeight="520.0" prefWidth="338.0" tableMenuButtonVisible="true" AnchorPane.bottomAnchor="178.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
              <columns>
                <TableColumn prefWidth="75.0" text="Name" fx:id="colName" />
                <TableColumn maxWidth="5000.0" minWidth="10.0" prefWidth="154.0" text="Surname" fx:id="colSurname" />
                <TableColumn maxWidth="5000.0" minWidth="10.0" prefWidth="112.0" text="Country" fx:id="colCountry" />
              </columns>
            </TableView>
          </children>
        </AnchorPane>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="404.0" prefWidth="460.0">
          <children>
            <Accordion layoutX="0.0" layoutY="0.0" prefHeight="520.0" prefWidth="262.0">
              <expandedPane>
                <TitledPane fx:id="personalTp" animated="false" text="Personal Details">
                  <content>
                    <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
                      <children>
                        <TextField fx:id="name" layoutX="44.0" layoutY="27.0" prefWidth="200.0" />
                      </children>
                    </AnchorPane>
                  </content>
                </TitledPane>
              </expandedPane>
              <panes>
                <fx:reference source="personalTp" />
                <TitledPane fx:id="x2" animated="false" text="Positions held">
                  <content>
                    <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
                      <children>
                         <ListView prefHeight="621.0" prefWidth="454.0" AnchorPane.bottomAnchor="-2.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="74.0" />
                      </children>
                    </AnchorPane>
                  </content>
                </TitledPane>
              </panes>
            </Accordion>
          </children>
        </AnchorPane>
      </items>
    </SplitPane>
    <MenuBar layoutY="0.0" AnchorPane.rightAnchor="908.0">
      <menus>
        <Menu mnemonicParsing="false" text="File">
          <items>
            <MenuItem mnemonicParsing="false" text="Close" />
          </items>
        </Menu>
        <Menu mnemonicParsing="false" text="Edit">
          <items>
            <MenuItem mnemonicParsing="false" text="Delete" />
          </items>
        </Menu>
        <Menu mnemonicParsing="false" text="Help">
          <items>
            <MenuItem mnemonicParsing="false" text="About" />
          </items>
        </Menu>
      </menus>
    </MenuBar>
    <ToolBar layoutY="24.0" AnchorPane.leftAnchor="0.0">
      <items>
        <Button mnemonicParsing="false" text="Button" />
      </items>
    </ToolBar>
  </children>
</AnchorPane>

JavaFXDemoProject.java

public class JavaFXDemoProject extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);

        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

Questions

1) Is it at all possible what I am trying to do?

2) Why isn't this working with bidirectionalBinding

Any help appreciated

标签: java javafx-2
1条回答
萌系小妹纸
2楼-- · 2019-08-30 07:16

I changed your controller class like this

public void initialize(URL url, ResourceBundle rb) {
    assert tableview != null : "fx:id=\"tableview\" was not injected: check your FXML file 'UserMaster.fxml'.";
 colName.setCellValueFactory(
    new PropertyValueFactory<Person,String>("name"));        
colSurname.setCellValueFactory(                
    new PropertyValueFactory<Person,String>("surname"));
colCountry.setCellValueFactory(
    new PropertyValueFactory<Person,String>("country"));     

buildData();
tableview.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {
        @Override
        public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {
            if (oldValue !=null) name.textProperty().unbindBidirectional(oldValue.nameProperty());
            if (newValue !=null) name.textProperty().bindBidirectional(newValue.nameProperty());
        }
    });
}    //initialize

and your person class a bit

public class Person {
private StringProperty name = new SimpleStringProperty();
private StringProperty surname = new SimpleStringProperty();
private StringProperty country = new SimpleStringProperty();

public Person(String name, String surname, String country){
    this.name.set(name);
    this.surname.set(surname);
    this.country.set(country);
}

public StringProperty nameProperty(){return name;}
public StringProperty surnameProperty(){return surname;}
public StringProperty countryProperty(){return country;}

}

Now the TextField can bind to the property in Person

查看更多
登录 后发表回答