Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javafx:如何使TableCell Edit返回双精度而不是字符串,并且字体根据条件改变颜色?_Java_Javafx - Fatal编程技术网

javafx:如何使TableCell Edit返回双精度而不是字符串,并且字体根据条件改变颜色?

javafx:如何使TableCell Edit返回双精度而不是字符串,并且字体根据条件改变颜色?,java,javafx,Java,Javafx,我有一个带有 public class Trade { private DoubleProperty price; private ReadOnlyBooleanWrapper caution; public Trade(double price){ this.price = new SimpleDoubleProperty(price); this.caution = new ReadOnlyBooleanWrapper();

我有一个带有

public class Trade {
    private DoubleProperty price;
    private ReadOnlyBooleanWrapper caution;

    public Trade(double price){
        this.price = new SimpleDoubleProperty(price);
        this.caution = new ReadOnlyBooleanWrapper();
        this.caution.bind(this.volume.greaterThan(0));
    }   

    public double getPrice(){
        return this.price.get();
    }   

    public DoubleProperty priceProperty(){
        return this.price;
    }

    public void setPrice(double price){
        this.price.set(price);
    }
}
在我的控制器类中,我有以下
TableView
TableColumn

问题有两个方面:

  • price属性和price列只接受
    double
    。但是下面的EditingDoubleCell代码只返回字符串如何使其返回双精度,并且用户键入的所有
    字符串将被忽略?
  • 我想要的第二个功能是:
    Price
    列的单元格内的字体(谈论相同的价格单元格)将在
    caution
    属性为true时颜色更改为蓝色,在
    caution
    属性为false时颜色更改为红色

  • 公共类EditingDoubleCell扩展了TableCell{
    私有文本字段文本字段;
    公共编辑DoubleCell(){
    }
    @凌驾
    公开作废已启动IT(){
    如果(!isEmpty()){
    super.startEdit();
    createTextField();
    setText(空);
    设置图形(文本字段);
    textField.requestFocus();
    //textField.selectAll();
    }
    }
    @凌驾
    公共作废取消编辑(){
    super.cancelEdit();
    setText((字符串)getItem());
    设置图形(空);
    }
    @凌驾
    public void updateItem(字符串项,布尔值为空){
    super.updateItem(项,空);
    if(空){
    setText(空);
    设置图形(空);
    }否则{
    if(isEditing()){
    if(textField!=null){
    setText(getString());
    }
    setText(空);
    设置图形(文本字段);
    }否则{
    setText(getString());
    设置图形(空);
    }
    }
    }
    私有字符串getString(){
    返回getItem()==null?”:getItem().toString();
    }
    私有void createTextField(){
    语言环境=新语言环境(“英语”、“英国”);
    字符串模式=“####,####.##”;
    DecimalFormat df=(DecimalFormat)NumberFormat.getNumberInstance(locale);
    df.应用模式(模式);
    //字符串格式=df.format(123456789.123);
    //System.out.println(格式);
    //NumberFormat nf=NumberFormat.getIntegerInstance();
    textField=新的textField();
    //添加筛选器以只允许键入整数
    textField.setTextFormatter(新的TextFormatter(c->
    {
    if(c.getControlNewText().isEmpty()){
    返回c;
    }
    ParsePosition ParsePosition=新的ParsePosition(0);
    Object Object=df.parse(c.getControlNewText(),parsePosition);
    if(object==null | | parsePosition.getIndex()公共无效改变(ObservalEvalue我有类似的问题,我做了如下操作:

    SimpleDoubleProperty price = new SimpleDoubleProperty();
    price.setValue(Double.parseDouble(EditingDoubleCell().getString()));
    ObservableValue<Double> g = price.asObject();
    return g;
    
    SimpleDoubleProperty price=new SimpleDoubleProperty();
    price.setValue(Double.parseDouble(EditingDoubleCell().getString());
    ObservableValue g=price.asObject();
    返回g;
    
    此方法预期您可以将字符串解析为double。
    对我有用,告诉我是否有用:)

    问题的第一部分:你可以试试下面的课程(它对我有用):


    对于问题的第一部分,您应该将
    TextFormatter
    创建为
    TextFormatter
    。这使
    TextFormatter
    valueProperty
    成为
    属性
    ,因此您可以通过调用
    getValue()提交编辑
    在格式化程序上。您需要指定一个
    StringConverter
    ,以便它知道如何从文本转换为
    Double
    ,反之亦然。因此如下所示:

            StringConverter<Double> converter = new StringConverter<Double>() {
    
                @Override
                public String toString(Double number) {
                    return df.format(number);
                }
    
                @Override
                public Double fromString(String string) {
                    try {
                        double value = df.parse(string).doubleValue() ;
                        return value;
                    } catch (ParseException e) {
                        e.printStackTrace();
                        return 0.0 ;
                    }
                }
    
            };
    
            textFormatter = new TextFormatter<>(converter,  0.0, c -> {
                if (partialInputPattern.matcher(c.getControlNewText()).matches()) {
                    return c ;
                } else {
                    return null ;
                }
            }) ;
    
    这是相当宽容的

    现在,不必在用户点击enter键时直接提交编辑,只需在文本格式化程序的值更改时提交编辑即可:

        // commit on Enter
        textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
            commitEdit(newValue);
        });
    
    整个cell类现在看起来像

    public static class EditingDoubleCell extends TableCell<Trade,Double>{
    
        private TextField textField;
        private TextFormatter<Double> textFormatter ;
    
        private DecimalFormat df ;
    
        public EditingDoubleCell(String...styleClasses) {
            Locale locale  = new Locale("en", "UK");
            String pattern = "###,###.###";
            df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
            df.applyPattern(pattern);
    
            getStyleClass().addAll(styleClasses);
        }
    
        @Override
        public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                textField.requestFocus();
            }
        }
    
        @Override
        public void cancelEdit() {
            super.cancelEdit();
            setText(df.format(getItem()));
            setGraphic(null);
        }
    
    
        @Override
        public void updateItem(Double item, boolean empty) {
            super.updateItem(item, empty);
    
            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                if (isEditing()) {
                    if (textField != null) {
                        textField.setText(getString());
    
                    }
                    setText(null);
                    setGraphic(textField);
                } else {
                    setText(getString());
                    setGraphic(null);
                }
            }
        }
    
        private String getString() {
            return getItem() == null ? "" : df.format(getItem());
        }
    
        private void createTextField(){
    
            textField = new TextField();
    
            StringConverter<Double> converter = new StringConverter<Double>() {
    
                @Override
                public String toString(Double number) {
                    return df.format(number);
                }
    
                @Override
                public Double fromString(String string) {
                    try {
                        double value = df.parse(string).doubleValue() ;
                        return value;
                    } catch (ParseException e) {
                        e.printStackTrace();
                        return 0.0 ;
                    }
                }
    
            };
    
            textFormatter = new TextFormatter<>(converter,  0.0, c ->
            {
                if (c.getControlNewText().isEmpty()) {
                    return c;
                }
                ParsePosition parsePosition = new ParsePosition( 0 );
                Object object = df.parse( c.getControlNewText(), parsePosition );
    
                if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() )
                {
                    return null;
                }
                else
                {
                    return c;
                }
            } ) ;
    
            // add filter to allow for typing only integer
            textField.setTextFormatter( textFormatter);
    
            textField.setText( getString() );
    
            textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
    
            // commit on Enter
            textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
                commitEdit(newValue);
            });
        }
    }
    
    然后只需在要更改样式的单元格上设置一个样式类(例如,将样式类
    “price cell”
    添加到您定义的
    EditingDoubleCell
    ),然后您可以根据需要使用CSS样式表来更改样式,例如

    .table-row-cell .price-cell {
        -fx-text-fill: red ;
    }
    
    .table-row-cell:caution .price-cell {
        -fx-text-fill: blue ;
    }
    
    对于未设置<代码>警告
    的行,将价格单元格的文本设为红色,对于设置了<代码>的行,将文本设为蓝色

    以下是完整的SSCCE:

    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    import java.text.ParseException;
    import java.text.ParsePosition;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;
    import java.util.Random;
    import java.util.function.Function;
    import java.util.regex.Pattern;
    
    import javafx.application.Application;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.ReadOnlyBooleanProperty;
    import javafx.beans.property.ReadOnlyBooleanWrapper;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.css.PseudoClass;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.TableCell;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableRow;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextField;
    import javafx.scene.control.TextFormatter;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    import javafx.util.StringConverter;
    
    public class TradeTable extends Application {
    
        private final Random rng = new Random();
    
        @Override
        public void start(Stage primaryStage) {
            TableView<Trade> table = new TableView<>();
            table.setEditable(true);
            TableColumn<Trade, Integer> volumeCol = column("Volume", trade -> trade.volumeProperty().asObject());
            TableColumn<Trade, Double> priceCol = column("Price", trade -> trade.priceProperty().asObject());
    
            priceCol.setCellFactory(col -> new EditingDoubleCell("price-cell"));
    
            table.getColumns().add(volumeCol);
            table.getColumns().add(priceCol);
    
            PseudoClass caution = PseudoClass.getPseudoClass("caution");
    
            table.setRowFactory(tv -> {
                TableRow<Trade> row = new TableRow<>();
    
                ChangeListener<Boolean> cautionListener = (obs, wasCaution, isNowCaution) -> 
                    row.pseudoClassStateChanged(caution, isNowCaution);
    
                row.itemProperty().addListener((obs, oldTrade, newTrade) -> {
                    if (oldTrade != null) {
                        oldTrade.cautionProperty().removeListener(cautionListener);
                    }
                    if (newTrade == null) {
                        row.pseudoClassStateChanged(caution, false);
                    } else {
                        row.pseudoClassStateChanged(caution, newTrade.isCaution());
                        newTrade.cautionProperty().addListener(cautionListener);
                    }
                });
    
                return row ;
            });
    
            table.getItems().addAll(createRandomData());
    
            Button button = new Button("Change Data");
            button.setOnAction(e -> table.getItems().forEach(trade -> {
                if (rng.nextDouble() < 0.5) {
                    trade.setVolume(0);
                } else {
                    trade.setVolume(rng.nextInt(10000));
                }
                trade.setPrice(rng.nextDouble() * 1000);
            }));
            BorderPane.setAlignment(button, Pos.CENTER);
            BorderPane.setMargin(button, new Insets(10));
    
            BorderPane root = new BorderPane(table, null, null, button, null);
            Scene scene = new Scene(root, 600, 600);
            scene.getStylesheets().add("trade-table.css");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private  List<Trade> createRandomData() {
            List<Trade> trades = new ArrayList<>(50);
            for (int i = 0 ; i < 50; i++) {
                int volume = rng.nextDouble() < 0.5 ? 0 : rng.nextInt(10000) ;
                double price = rng.nextDouble() * 10000 ;
                trades.add(new Trade(price, volume));
            }
            return trades ;
        }
    
        private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
            TableColumn<S,T> col = new TableColumn<>(title);
            col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
            return col ;
        }
    
        public static class Trade {
            private DoubleProperty price;
            private IntegerProperty volume ;
            private ReadOnlyBooleanWrapper caution;
    
            public Trade(double price, int volume){
                this.price = new SimpleDoubleProperty(price);
                this.volume = new SimpleIntegerProperty(volume);
                this.caution = new ReadOnlyBooleanWrapper();
                this.caution.bind(this.volume.greaterThan(0));
            }   
    
            public double getPrice(){
                return this.price.get();
            }   
    
            public DoubleProperty priceProperty(){
                return this.price;
            }
    
            public void setPrice(double price){
                this.price.set(price);
            }
    
            public final IntegerProperty volumeProperty() {
                return this.volume;
            }
    
            public final int getVolume() {
                return this.volumeProperty().get();
            }
    
            public final void setVolume(final int volume) {
                this.volumeProperty().set(volume);
            }
    
            public final ReadOnlyBooleanProperty cautionProperty() {
                return this.caution.getReadOnlyProperty();
            }
    
            public final boolean isCaution() {
                return this.cautionProperty().get();
            }
    
    
        }
    
        public static class EditingDoubleCell extends TableCell<Trade,Double>{
    
            private TextField textField;
            private TextFormatter<Double> textFormatter ;
    
            private Pattern partialInputPattern = Pattern.compile(
                    "[-+]?[,0-9]*(\\.[0-9]*)?");
    
            private DecimalFormat df ;
    
            public EditingDoubleCell(String...styleClasses) {
                Locale locale  = new Locale("en", "UK");
                String pattern = "###,###.###";
                df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
                df.applyPattern(pattern);
    
                getStyleClass().addAll(styleClasses);
            }
    
            @Override
            public void startEdit() {
                if (!isEmpty()) {
                    super.startEdit();
                    createTextField();
                    setText(null);
                    setGraphic(textField);
                    textField.requestFocus();
                }
            }
    
            @Override
            public void cancelEdit() {
                super.cancelEdit();
                setText(df.format(getItem()));
                setGraphic(null);
            }
    
    
            @Override
            public void updateItem(Double item, boolean empty) {
                super.updateItem(item, empty);
    
                if (empty) {
                    setText(null);
                    setGraphic(null);
                } else {
                    if (isEditing()) {
                        if (textField != null) {
                            textField.setText(getString());
    
                        }
                        setText(null);
                        setGraphic(textField);
                    } else {
                        setText(getString());
                        setGraphic(null);
                    }
                }
            }
    
            private String getString() {
                return getItem() == null ? "" : df.format(getItem());
            }
    
            private void createTextField(){
    
                textField = new TextField();
    
                StringConverter<Double> converter = new StringConverter<Double>() {
    
                    @Override
                    public String toString(Double number) {
                        return df.format(number);
                    }
    
                    @Override
                    public Double fromString(String string) {
                        try {
                            double value = df.parse(string).doubleValue() ;
                            return value;
                        } catch (ParseException e) {
                            e.printStackTrace();
                            return 0.0 ;
                        }
                    }
    
                };
    
                textFormatter = new TextFormatter<>(converter,  0.0, c -> {
                    if (partialInputPattern.matcher(c.getControlNewText()).matches()) {
                        return c ;
                    } else {
                        return null ;
                    }
                }) ;
    
                // add filter to allow for typing only integer
                textField.setTextFormatter( textFormatter);
    
                textField.setText( getString() );
    
                textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
    
                // commit on Enter
                textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
                    commitEdit(newValue);
                });
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    导入java.text.DecimalFormat;
    导入java.text.NumberFormat;
    导入java.text.ParseException;
    导入java.text.ParsePosition;
    导入java.util.ArrayList;
    导入java.util.List;
    导入java.util.Locale;
    导入java.util.Random;
    导入java.util.function.function;
    导入java.util.regex.Pattern;
    导入javafx.application.application;
    导入javafx.beans.property.DoubleProperty;
    导入javafx.beans.property.IntegerProperty;
    导入javafx.beans.property.ReadOnlyBooleanProperty;
    导入javafx.beans.property.ReadOnlyBooleanWrapper;
    导入javafx.beans.property.SimpleDoubleProperty;
    导入javafx.beans.property.SimpleIntegerProperty;
    导入javafx.beans.value.ChangeListener;
    导入javafx.beans.value.observeValue;
    导入javafx.css.pseudo类;
    进口
    
        // commit on Enter
        textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
            commitEdit(newValue);
        });
    
    public static class EditingDoubleCell extends TableCell<Trade,Double>{
    
        private TextField textField;
        private TextFormatter<Double> textFormatter ;
    
        private DecimalFormat df ;
    
        public EditingDoubleCell(String...styleClasses) {
            Locale locale  = new Locale("en", "UK");
            String pattern = "###,###.###";
            df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
            df.applyPattern(pattern);
    
            getStyleClass().addAll(styleClasses);
        }
    
        @Override
        public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                textField.requestFocus();
            }
        }
    
        @Override
        public void cancelEdit() {
            super.cancelEdit();
            setText(df.format(getItem()));
            setGraphic(null);
        }
    
    
        @Override
        public void updateItem(Double item, boolean empty) {
            super.updateItem(item, empty);
    
            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                if (isEditing()) {
                    if (textField != null) {
                        textField.setText(getString());
    
                    }
                    setText(null);
                    setGraphic(textField);
                } else {
                    setText(getString());
                    setGraphic(null);
                }
            }
        }
    
        private String getString() {
            return getItem() == null ? "" : df.format(getItem());
        }
    
        private void createTextField(){
    
            textField = new TextField();
    
            StringConverter<Double> converter = new StringConverter<Double>() {
    
                @Override
                public String toString(Double number) {
                    return df.format(number);
                }
    
                @Override
                public Double fromString(String string) {
                    try {
                        double value = df.parse(string).doubleValue() ;
                        return value;
                    } catch (ParseException e) {
                        e.printStackTrace();
                        return 0.0 ;
                    }
                }
    
            };
    
            textFormatter = new TextFormatter<>(converter,  0.0, c ->
            {
                if (c.getControlNewText().isEmpty()) {
                    return c;
                }
                ParsePosition parsePosition = new ParsePosition( 0 );
                Object object = df.parse( c.getControlNewText(), parsePosition );
    
                if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() )
                {
                    return null;
                }
                else
                {
                    return c;
                }
            } ) ;
    
            // add filter to allow for typing only integer
            textField.setTextFormatter( textFormatter);
    
            textField.setText( getString() );
    
            textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
    
            // commit on Enter
            textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
                commitEdit(newValue);
            });
        }
    }
    
    PseudoClass caution = PseudoClass.getPseudoClass("caution");
    
    table.setRowFactory(tv -> {
        TableRow<Trade> row = new TableRow<>();
    
        ChangeListener<Boolean> cautionListener = (obs, wasCaution, isNowCaution) -> 
            row.pseudoClassStateChanged(caution, isNowCaution);
    
        row.itemProperty().addListener((obs, oldTrade, newTrade) -> {
            if (oldTrade != null) {
                oldTrade.cautionProperty().removeListener(cautionListener);
            }
            if (newTrade == null) {
                row.pseudoClassStateChanged(caution, false);
            } else {
                row.pseudoClassStateChanged(caution, newTrade.isCaution());
                newTrade.cautionProperty().addListener(cautionListener);
            }
        });
    
        return row ;
    });
    
    .table-row-cell .price-cell {
        -fx-text-fill: red ;
    }
    
    .table-row-cell:caution .price-cell {
        -fx-text-fill: blue ;
    }
    
    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    import java.text.ParseException;
    import java.text.ParsePosition;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;
    import java.util.Random;
    import java.util.function.Function;
    import java.util.regex.Pattern;
    
    import javafx.application.Application;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.ReadOnlyBooleanProperty;
    import javafx.beans.property.ReadOnlyBooleanWrapper;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.css.PseudoClass;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.TableCell;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableRow;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextField;
    import javafx.scene.control.TextFormatter;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    import javafx.util.StringConverter;
    
    public class TradeTable extends Application {
    
        private final Random rng = new Random();
    
        @Override
        public void start(Stage primaryStage) {
            TableView<Trade> table = new TableView<>();
            table.setEditable(true);
            TableColumn<Trade, Integer> volumeCol = column("Volume", trade -> trade.volumeProperty().asObject());
            TableColumn<Trade, Double> priceCol = column("Price", trade -> trade.priceProperty().asObject());
    
            priceCol.setCellFactory(col -> new EditingDoubleCell("price-cell"));
    
            table.getColumns().add(volumeCol);
            table.getColumns().add(priceCol);
    
            PseudoClass caution = PseudoClass.getPseudoClass("caution");
    
            table.setRowFactory(tv -> {
                TableRow<Trade> row = new TableRow<>();
    
                ChangeListener<Boolean> cautionListener = (obs, wasCaution, isNowCaution) -> 
                    row.pseudoClassStateChanged(caution, isNowCaution);
    
                row.itemProperty().addListener((obs, oldTrade, newTrade) -> {
                    if (oldTrade != null) {
                        oldTrade.cautionProperty().removeListener(cautionListener);
                    }
                    if (newTrade == null) {
                        row.pseudoClassStateChanged(caution, false);
                    } else {
                        row.pseudoClassStateChanged(caution, newTrade.isCaution());
                        newTrade.cautionProperty().addListener(cautionListener);
                    }
                });
    
                return row ;
            });
    
            table.getItems().addAll(createRandomData());
    
            Button button = new Button("Change Data");
            button.setOnAction(e -> table.getItems().forEach(trade -> {
                if (rng.nextDouble() < 0.5) {
                    trade.setVolume(0);
                } else {
                    trade.setVolume(rng.nextInt(10000));
                }
                trade.setPrice(rng.nextDouble() * 1000);
            }));
            BorderPane.setAlignment(button, Pos.CENTER);
            BorderPane.setMargin(button, new Insets(10));
    
            BorderPane root = new BorderPane(table, null, null, button, null);
            Scene scene = new Scene(root, 600, 600);
            scene.getStylesheets().add("trade-table.css");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private  List<Trade> createRandomData() {
            List<Trade> trades = new ArrayList<>(50);
            for (int i = 0 ; i < 50; i++) {
                int volume = rng.nextDouble() < 0.5 ? 0 : rng.nextInt(10000) ;
                double price = rng.nextDouble() * 10000 ;
                trades.add(new Trade(price, volume));
            }
            return trades ;
        }
    
        private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
            TableColumn<S,T> col = new TableColumn<>(title);
            col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
            return col ;
        }
    
        public static class Trade {
            private DoubleProperty price;
            private IntegerProperty volume ;
            private ReadOnlyBooleanWrapper caution;
    
            public Trade(double price, int volume){
                this.price = new SimpleDoubleProperty(price);
                this.volume = new SimpleIntegerProperty(volume);
                this.caution = new ReadOnlyBooleanWrapper();
                this.caution.bind(this.volume.greaterThan(0));
            }   
    
            public double getPrice(){
                return this.price.get();
            }   
    
            public DoubleProperty priceProperty(){
                return this.price;
            }
    
            public void setPrice(double price){
                this.price.set(price);
            }
    
            public final IntegerProperty volumeProperty() {
                return this.volume;
            }
    
            public final int getVolume() {
                return this.volumeProperty().get();
            }
    
            public final void setVolume(final int volume) {
                this.volumeProperty().set(volume);
            }
    
            public final ReadOnlyBooleanProperty cautionProperty() {
                return this.caution.getReadOnlyProperty();
            }
    
            public final boolean isCaution() {
                return this.cautionProperty().get();
            }
    
    
        }
    
        public static class EditingDoubleCell extends TableCell<Trade,Double>{
    
            private TextField textField;
            private TextFormatter<Double> textFormatter ;
    
            private Pattern partialInputPattern = Pattern.compile(
                    "[-+]?[,0-9]*(\\.[0-9]*)?");
    
            private DecimalFormat df ;
    
            public EditingDoubleCell(String...styleClasses) {
                Locale locale  = new Locale("en", "UK");
                String pattern = "###,###.###";
                df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
                df.applyPattern(pattern);
    
                getStyleClass().addAll(styleClasses);
            }
    
            @Override
            public void startEdit() {
                if (!isEmpty()) {
                    super.startEdit();
                    createTextField();
                    setText(null);
                    setGraphic(textField);
                    textField.requestFocus();
                }
            }
    
            @Override
            public void cancelEdit() {
                super.cancelEdit();
                setText(df.format(getItem()));
                setGraphic(null);
            }
    
    
            @Override
            public void updateItem(Double item, boolean empty) {
                super.updateItem(item, empty);
    
                if (empty) {
                    setText(null);
                    setGraphic(null);
                } else {
                    if (isEditing()) {
                        if (textField != null) {
                            textField.setText(getString());
    
                        }
                        setText(null);
                        setGraphic(textField);
                    } else {
                        setText(getString());
                        setGraphic(null);
                    }
                }
            }
    
            private String getString() {
                return getItem() == null ? "" : df.format(getItem());
            }
    
            private void createTextField(){
    
                textField = new TextField();
    
                StringConverter<Double> converter = new StringConverter<Double>() {
    
                    @Override
                    public String toString(Double number) {
                        return df.format(number);
                    }
    
                    @Override
                    public Double fromString(String string) {
                        try {
                            double value = df.parse(string).doubleValue() ;
                            return value;
                        } catch (ParseException e) {
                            e.printStackTrace();
                            return 0.0 ;
                        }
                    }
    
                };
    
                textFormatter = new TextFormatter<>(converter,  0.0, c -> {
                    if (partialInputPattern.matcher(c.getControlNewText()).matches()) {
                        return c ;
                    } else {
                        return null ;
                    }
                }) ;
    
                // add filter to allow for typing only integer
                textField.setTextFormatter( textFormatter);
    
                textField.setText( getString() );
    
                textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
    
                // commit on Enter
                textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
                    commitEdit(newValue);
                });
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }