简体   繁体   中英

Editing numbers in javafx TableView cells

I'm making a fairly involved desktop application for a friend as a way of learning Java, and in particular Java 8 and JavaFX. The application will have lots of tables and work like a highly-specific spreadsheet, and is to do with estimating shipping costs. So far I have learned to use Scene Builder, and using css structures, and devised my own classes to represent the data in the tables. This is a cut-down version of my Vessel class:

    import javafx.beans.property.*; 

public class Vessel
{
    private  StringProperty name;
    private  FloatProperty deadWeight;

    public Vessel(){
        this.name = new SimpleStringProperty("ENTER SHIP NAME");
        this.deadWeight = new SimpleFloatProperty(0);
    }

    public Vessel(String name, float deadWeight){
        this.name = new SimpleStringProperty(name);
    }

    public void setName(String name){this.name.set(name);}
    public void setDeadWeight(float deadWeight){this.deadWeight.set(deadWeight);}   

    public String getName(){
        if ( !(name.get().equals("")) || (name.get()==null) || (name.get().trim().equals("ENTER SHIP NAME")) )
            return name.get();
      return null;
    }

    public float getDeadWeight(){return  deadWeight.get();} 

    public StringProperty nameProperty() { return name;}
    public FloatProperty deadWeightProperty() { return deadWeight;}

    public void clear(){
            this.name.set("ENTER SHIP NAME");
            this.deadWeight.set(0);
    }
}

I need to directly edit cells in TableView, which are either floats or Strings. I can do this with strings, from information I've gleaned on this site, but can't figure out how to do floats.

Here is the controller file, VesselController.java:

    import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.AnchorPane; 
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.value.*;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;

 public class VesselController {  

    @FXML  private AnchorPane root;
    @FXML  private TableView<Vessel> vesselTable;
    @FXML  private TableColumn<Vessel, String> vesselTableNameCol;
    @FXML  private TableColumn<Vessel, Number> vesselTableDWTCol;

    // Reference to the main application.
    private MyMain mainApp;

    //The constructor, it is called before the initialize() method.
    public VesselController() {}

    //Initializes the controller class. This method is automatically called after the fxml file has been loaded.
    @FXML
    private void initialize() {
        // Initialize the vessel table with the columns.
      vesselTableNameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
        vesselTableNameCol.setCellFactory(column -> EditCell.createStringEditCell());

      vesselTableDWTCol.setCellValueFactory(cellData -> cellData.getValue().deadWeightProperty());

        // vesselTableDWTCol.setCellFactory(column -> EditCell.createStringEditCell()); //not working, as it needs to reurn a SimpleFloatProperty type
        //so tried this, but don't have a clear idea of what I'm doing
        vesselTableDWTCol.setCellValueFactory(new Callback<CellDataFeatures<Vessel, Number>, ObservableValue<Number>>() {
                @Override
                public ObservableValue<Number> call(CellDataFeatures<Vessel, Number> p) {
                return new SimpleFloatProperty(p.getValue().deadWeightProprerty());
                } 
            });

    }

    //Is called by the main application to give a reference back to itself.
    public void setMainApp(MyMain mainApp) {
      this.mainApp = mainApp;
      vesselTable.setItems(mainApp.getVesselData());   // Add observable list data to the table
        vesselTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
       vesselTable.setEditable(true);
    }
}

This is the class that displays errors, and I'm not sure why-- do I need to implement a Callback? If so how do I do this? Some of this code I gleaned from this post , to try to make it work with Numbers. The EditCell class I downloaded from James_D's repository .

And here is the MyMain.java to run it:

    import java.io.*;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene; 
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.collections.ObservableList;
import javafx.collections.FXCollections;

public class MyMain extends Application {
    private Stage primaryStage;

    //The data as an observable list of Persons.
    private ObservableList<Vessel> vesselData = FXCollections.observableArrayList();

    //Constructor
   public MyMain() {          // Add some sample data
         vesselData.add(new Vessel()); //init empty row
    }

    // Returns the data as an observable list of Vessels (in this case a single row) 
    public ObservableList<Vessel> getVesselData() { return vesselData; }

    // Shows the vessel overview inside the root layout.
    @Override
    public void start(Stage primaryStage) { 
        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("My Vessel");      
        show();
     }

    //Initializes the root layout. 
    public void show() {
        try {          
            FXMLLoader loader = new FXMLLoader(); // Load root layout from fxml file.
            loader.setLocation(MyMain.class.getResource("MyUI.fxml"));
            AnchorPane root = (AnchorPane) loader.load();

                // Give the controller access to the main app.
                VesselController controller = loader.getController();
                controller.setMainApp(this);

            // Show the scene containing the root layout.
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException e) { e.printStackTrace();}
    } 

    // Returns the main stage.
    public Stage getPrimaryStage() {
        return primaryStage;
    }

    public static void main(String[] args) { 
        Application.launch(MyMain.class, (java.lang.String[])null);
    }
}

I'm pretty sure I need to modify the EditCell class, and I've tried to create my own "NumberConverter" without any luck-- I don't fully understand generification, but I'm pretty sure I need to go down that path due to the overall final complexity of the application. Apologies for such a lengthy post.

If anyone can provide some guidance that would be great.

I think you don't need to use EditCell class. Alternatively, you can use TextFieldTableCell class. You need to call setcellfactory(...) method for vesselTableDWTCol column (you can do same thing with vesselTableNameCol column).

Use the following snippet of code:

// this line allow you to edit  cells in `vesselTableNameCol` column 
    vesselTableNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
// this line allow you to edit  cells in `vesselTableDWTCol` column
    vesselTableDWTCol.setCellFactory(TextFieldTableCell.forTableColumn(new FloatStringConverter()));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM