如何在JavaFX可编辑的TreeTableView中提供对货币(LongProperty)的编辑?

huangapple go评论91阅读模式
英文:

How to provide Editing of a currency (LongProperty) within a JavaFX editable TreeTableView?

问题

以下是您提供的内容的中文翻译:

如何将BO货币(LongProperty)绑定到JavaFX可编辑的TreeTableView?使用数据绑定、TextFormatter和其他JavaFX工具。

对于普通的TextField,我找到了这个解决方案:使用TextField编辑货币

BO:

import java.util.Random;

import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;

public class SimpleBo {
    // 一个简单的LongProperty,用于存储没有小数位的货币(56,81 €将变为5681)
    private LongProperty currencyLong = new SimpleLongProperty();

    public SimpleBo() {
        setCurrencyLong(new Random().nextLong());
    }

    public final LongProperty currencyLongProperty() {
        return this.currencyLong;
    }

    public final long getCurrencyLong() {
        return this.currencyLongProperty().get();
    }

    public final void setCurrencyLong(final long currencyLong) {
        this.currencyLongProperty().set(currencyLong);
    }
}

应用程序:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TextFieldTreeTableCell;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.stage.Stage;

public class BindingExample extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        Scene scene = new Scene(createTreeTableView());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private static TreeTableView<SimpleBo> createTreeTableView() {
        TreeTableView<SimpleBo> treeTableView = new TreeTableView<>();

        // 创建列(Long数据类型)。
        TreeTableColumn<SimpleBo, Number> currencyColumn = new TreeTableColumn<>("货币");

        // 绑定值
        currencyColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("currencyLong"));

        // 设置单元格工厂
        currencyColumn.setCellFactory(param -> new TextFieldTreeTableCell<>());

        // 将列添加到TreeTable中。
        treeTableView.getColumns().add(currencyColumn);

        SimpleBo firstBo = new SimpleBo();
        SimpleBo secondBo = new SimpleBo();
        SimpleBo thirdBo = new SimpleBo();

        // 根项目
        TreeItem<SimpleBo> itemRoot = new TreeItem<>(null);
        TreeItem<SimpleBo> itemFirst = new TreeItem<>(firstBo);
        TreeItem<SimpleBo> itemSecond = new TreeItem<>(secondBo);
        TreeItem<SimpleBo> itemThird = new TreeItem<>(thirdBo);

        itemRoot.getChildren().addAll(itemFirst, itemSecond, itemThird);

        // 为Tree设置根项目
        treeTableView.setRoot(itemRoot);
        treeTableView.setShowRoot(false);
        treeTableView.setEditable(true);

        return treeTableView;
    }
}

目标是:

  • 带有LongProperty的BO(以分为单位的货币值)
  • 可编辑的TreeTable,按照用户已知的格式(可选的负号、千位分隔符、小数点分隔符、货币符号,不允许其他字符)
  • BO和TreeTableColumn之间的双向绑定。
英文:

How do I bind a BO currency (LongProperty) to a Javafx editable TreeTableView? Using Databinding, TextFormatter and other javaFX Stuff.

For a normal TextField I found this solution: Editiing Currency with a TextField

Bo:

import java.util.Random;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
public class SimpleBo {
//a simple LongProperty to store the currency without fractional digits (56,81 € would be 5681)
private LongProperty currencyLong = new SimpleLongProperty();
public SimpleBo() {
setCurrencyLong(new Random().nextLong());
}
public final LongProperty currencyLongProperty() {
return this.currencyLong;
}
public final long getCurrencyLong() {
return this.currencyLongProperty().get();
}
public final void setCurrencyLong(final long currencyLong) {
this.currencyLongProperty().set(currencyLong);
}
}

Application:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TextFieldTreeTableCell;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.stage.Stage;
public class BindingExample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createTreeTableView());
primaryStage.setScene(scene);
primaryStage.show();
}
private static TreeTableView&lt;SimpleBo&gt; createTreeTableView() {
TreeTableView&lt;SimpleBo&gt; treeTableView = new TreeTableView&lt;&gt;();
// Create column (Data type of Long).
TreeTableColumn&lt;SimpleBo, Number&gt; currencyColumn = new TreeTableColumn&lt;&gt;(&quot;Currency&quot;);
//Bind Values
currencyColumn.setCellValueFactory(new TreeItemPropertyValueFactory&lt;&gt;(&quot;currencyLong&quot;));
//Set Cell Factory
currencyColumn.setCellFactory( param -&gt; new TextFieldTreeTableCell&lt;&gt;());
// Add columns to TreeTable.
treeTableView.getColumns().add(currencyColumn);
SimpleBo firstBo = new SimpleBo();
SimpleBo secondBo = new SimpleBo();
SimpleBo thirdBo = new SimpleBo();
// Root Item
TreeItem&lt;SimpleBo&gt; itemRoot = new TreeItem&lt;&gt;(null);
TreeItem&lt;SimpleBo&gt; itemFirst = new TreeItem&lt;&gt;(firstBo);
TreeItem&lt;SimpleBo&gt; itemSecond = new TreeItem&lt;&gt;(secondBo);
TreeItem&lt;SimpleBo&gt; itemThird = new TreeItem&lt;&gt;(thirdBo);
itemRoot.getChildren().addAll(itemFirst, itemSecond, itemThird);
// Set root Item for Tree
treeTableView.setRoot(itemRoot);
treeTableView.setShowRoot(false);
treeTableView.setEditable(true);
return treeTableView;
}
}

The goal should be:

  • Bo with a LongProperty (currency Value in cents)
  • editable TreeTable, in the Users known format (optinal leading minus,
    thousands separator, decimal separator, currency symbol, and no other
    chars possible)
  • BiDirectionalBinding between Bo and TreeTableColumn.

答案1

得分: 0

以下是您要翻译的内容:

A Solution would by a "CurrencyTextFieldTreeTableCell" with a custom Design.

use the MyNumberStringConverter and Util Class ([from this Answer][1])

CurrencyTextFieldTreeTableCell:

import javafx.geometry.Insets;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.util.Callback;

public class CurrencyTextFieldTreeTableCell extends TreeTableCell<SimpleBo, Number> {

    public static Callback<TreeTableColumn<SimpleBo, Number>, TreeTableCell<SimpleBo, Number>> forTreeTableColumn() {
        return forTreeTableColumn(new MyNumberStringConverter());
    }

    public static Callback<TreeTableColumn<SimpleBo, Number>, TreeTableCell<SimpleBo, Number>> forTreeTableColumn(
            final MyNumberStringConverter converter) {
        return list -> new CurrencyTextFieldTreeTableCell(converter);
    }

    /***************************************************************************
     * * Fields * *
     **************************************************************************/

    private HBox hBox = new HBox();
    private Label currencyLabel = new Label("€");
    private TextField textField = new TextField("" + 0l);

    /***************************************************************************
     * * Constructors * *
     **************************************************************************/

    public CurrencyTextFieldTreeTableCell() {
        this(new MyNumberStringConverter());
    }

    private CurrencyTextFieldTreeTableCell(MyNumberStringConverter converter) {
        this.getStyleClass().add("currency-text-field-tree-table-cell");
        this.converter = converter;
        setupTextField();
        setupHBox();
        setStyle("-fx-alignment: CENTER-RIGHT;");
    }

    /***************************************************************************
     * * Properties * *
     **************************************************************************/

    private MyNumberStringConverter converter = new MyNumberStringConverter();

    /** {@inheritDoc} */
    @Override
    public void startEdit() {
        if (!isEditable() || !getTreeTableView().isEditable() || !getTableColumn().isEditable()) {
            return;
        }
        super.startEdit();

        if (isEditing()) {
            this.setText(null);

            if (hBox != null) {
                this.setGraphic(hBox);
            } else {
                this.setGraphic(textField);
            }
            if (textField != null) {
                textField.setText(getItemText());
                textField.selectAll();
                // requesting focus so that key input can immediately go into the
                // TextField (see RT-28132)
                textField.requestFocus();
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public void cancelEdit() {
        super.cancelEdit();
        this.setText(getItemText());
        this.setGraphic(currencyLabel);
        contentDisplayProperty().setValue(ContentDisplay.RIGHT);
    }

    /** {@inheritDoc} */
    @Override
    public void updateItem(Number item, boolean empty) {
        super.updateItem(item, empty);
        if (isEmpty()) {
            setText(null);
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getItemText());
                }
                setText(null);
                setGraphic(hBox);
            } else {
                setText(getItemText());
                setGraphic(currencyLabel);
                contentDisplayProperty().setValue(ContentDisplay.RIGHT);
            }
        }
    }

    private void setupTextField() {
        TextFormatter<Number> textFormatter = new TextFormatter<>(Util.createFilter());
        this.textField.setTextFormatter(textFormatter);
        // Use onAction here rather than onKeyReleased (with check for Enter),
        // as otherwise we encounter RT-34685
        this.textField.setOnAction(event -> {
            if (converter == null) {
                throw new IllegalStateException("Attempting to convert text input into Object, but provided "
                        + "StringConverter is null. Be sure to set a StringConverter " + "in your cell factory.");
            }
            commitEdit(converter.fromString(textField.getText()).longValue());
            event.consume();
        });
        this.textField.setOnKeyReleased(t -> {
            if (t.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
                t.consume();
            }
        });
    }

    private void setupHBox() {
        this.hBox.getChildren().add(this.textField);
        this.hBox.getChildren().add(new Label(" €"));
        this.hBox.setPadding(new Insets(this.hBox.getPadding().getTop() + 9.0D, this.hBox.getPadding().getRight(), this.hBox.getPadding().getBottom(), this.hBox.getPadding().getLeft()));
    }

    private String getItemText() {
        if(converter == null) {
            return getItem() == null ? "" : getItem().toString();
        } else {
            return converter.toString(getItem());
        }
    }
}

并且将setCellFactory更改为以下内容:

NumberFormat nFormat = NumberFormat.getInstance();
nFormat.setMinimumIntegerDigits(1);
nFormat.setMinimumFractionDigits(2);
nFormat.setMaximumFractionDigits(2);
MyNumberStringConverter numberStringConverter = new MyNumberStringConverter(nFormat);
// Set Cell Factory
currencyColumn.setCellFactory(
        param -> CurrencyTextFieldTreeTableCell.forTreeTableColumn(numberStringConverter).call(param));

希望这对您有所帮助。

英文:

A Solution would by a "CurrencyTextFieldTreeTableCell" with a custom Design.

use the MyNumberStringConverter and Util Class (from this Answer)

CurrencyTextFieldTreeTableCell:

import javafx.geometry.Insets;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.util.Callback;
public class CurrencyTextFieldTreeTableCell extends TreeTableCell&lt;SimpleBo, Number&gt; {
public static Callback&lt;TreeTableColumn&lt;SimpleBo, Number&gt;, TreeTableCell&lt;SimpleBo, Number&gt;&gt; forTreeTableColumn() {
return forTreeTableColumn(new MyNumberStringConverter());
}
public static Callback&lt;TreeTableColumn&lt;SimpleBo, Number&gt;, TreeTableCell&lt;SimpleBo, Number&gt;&gt; forTreeTableColumn(
final MyNumberStringConverter converter) {
return list -&gt; new CurrencyTextFieldTreeTableCell(converter);
}
/***************************************************************************
* * Fields * *
**************************************************************************/
private HBox hBox = new HBox();
private Label currencyLabel = new Label(&quot;€&quot;);
private TextField textField = new TextField(&quot;&quot; + 0l);
/***************************************************************************
* * Constructors * *
**************************************************************************/
public CurrencyTextFieldTreeTableCell() {
this(new MyNumberStringConverter());
}
private CurrencyTextFieldTreeTableCell(MyNumberStringConverter converter) {
this.getStyleClass().add(&quot;currency-text-field-tree-table-cell&quot;);
this.converter = converter;
setupTextField();
setupHBox();
setStyle(&quot;-fx-alignment: CENTER-RIGHT;&quot;);
}
/***************************************************************************
* * Properties * *
**************************************************************************/
private MyNumberStringConverter converter = new MyNumberStringConverter();
/** {@inheritDoc} */
@Override
public void startEdit() {
if (!isEditable() || !getTreeTableView().isEditable() || !getTableColumn().isEditable()) {
return;
}
super.startEdit();
if (isEditing()) {
this.setText(null);
if (hBox != null) {
this.setGraphic(hBox);
} else {
this.setGraphic(textField);
}
if (textField != null) {
textField.setText(getItemText());
textField.selectAll();
// requesting focus so that key input can immediately go into the
// TextField (see RT-28132)
textField.requestFocus();
}
}
}
/** {@inheritDoc} */
@Override
public void cancelEdit() {
super.cancelEdit();
this.setText(getItemText());
this.setGraphic(currencyLabel);
contentDisplayProperty().setValue(ContentDisplay.RIGHT);
}
/** {@inheritDoc} */
@Override
public void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (isEmpty()) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getItemText());
}
setText(null);
setGraphic(hBox);
} else {
setText(getItemText());
setGraphic(currencyLabel);
contentDisplayProperty().setValue(ContentDisplay.RIGHT);
}
}
}
private void setupTextField() {
TextFormatter&lt;Number&gt; textFormatter = new TextFormatter&lt;&gt;(Util.createFilter());
this.textField.setTextFormatter(textFormatter);
// Use onAction here rather than onKeyReleased (with check for Enter),
// as otherwise we encounter RT-34685
this.textField.setOnAction(event -&gt; {
if (converter == null) {
throw new IllegalStateException(&quot;Attempting to convert text input into Object, but provided &quot;
+ &quot;StringConverter is null. Be sure to set a StringConverter &quot; + &quot;in your cell factory.&quot;);
}
commitEdit(converter.fromString(textField.getText()).longValue());
event.consume();
});
this.textField.setOnKeyReleased(t -&gt; {
if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
t.consume();
}
});
}
private void setupHBox() {
this.hBox.getChildren().add(this.textField);
this.hBox.getChildren().add(new Label(&quot; €&quot;));
this.hBox.setPadding(new Insets(this.hBox.getPadding().getTop() + 9.0D, this.hBox.getPadding().getRight(), this.hBox.getPadding().getBottom(), this.hBox.getPadding().getLeft()));
}
private String getItemText() {
if(converter == null) {
return getItem() == null ? &quot;&quot; : getItem().toString();
} else {
return converter.toString(getItem());
}
}
}

And change the setCellFactory to this:

	NumberFormat nFormat = NumberFormat.getInstance();
nFormat.setMinimumIntegerDigits(1);
nFormat.setMinimumFractionDigits(2);
nFormat.setMaximumFractionDigits(2);
MyNumberStringConverter numberStringConverter = new MyNumberStringConverter(nFormat);
// Set Cell Factory
currencyColumn.setCellFactory(
param -&gt; CurrencyTextFieldTreeTableCell.forTreeTableColumn(numberStringConverter).call(param));

huangapple
  • 本文由 发表于 2020年8月11日 13:26:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/63352009.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定