java - "Accounting"JavaFX 中的样式表单元格

标签 java javafx alignment tablecell

有没有办法在 JavaFX 表中创建“会计”样式的单元格? 通过会计,我的意思是让美元符号左对齐,值在单元格中右对齐。这是在 Excel 中的样子:

Excel Accounting Cell Format

到目前为止,这是我尝试过的:

public class PriceTableCell<S> extends TableCell<S, Long>
{
    public PriceTableCell()
    {
        final Label label = new Label("$");
        this.setAlignment(Pos.CENTER_RIGHT);
        this.setContentDisplay(ContentDisplay.LEFT);
        this.setGraphic(label);
    }

    @Override
    protected void updateItem(Long item, boolean empty)
    {
        if (item == null || empty)
        {
            this.setText(null);
            return;
        }

        this.setText(String.format(Locale.ENGLISH, "%,d.%02d", item / 100, Math.abs(item % 100)));
    }
}

不幸的是,我没有找到一种方法来为图形和文本设置单独的对齐方式。 JavaFX 将上述内容呈现如下:

JavaFX attempt

最佳答案

AnchorPane 中使用两个标签应该可行。

(更新:根据 @kleopatra 的建议,我将 DecimalFormat 合并到该解决方案中,它将(至少部分地)本地化货币符号以及小数位数,等等。这将假设货币符号显示在货币值的左侧,这不一定适用于所有货币,但无论如何该假设在某种程度上隐含在问题中。)

public class PriceTableCell<S> extends TableCell<S, Long> {

    private final AnchorPane pane ;
    private final Label valueLabel ;
    // locale-aware currency format to use for formatting
    private DecimalFormat format;

    public PriceTableCell() {
        // grab an instance
        format = (DecimalFormat) NumberFormat.getCurrencyInstance();
        //get the currency symbol
        String symbol = format.getCurrency().getSymbol();
        // replace the currency symbol with an empty string
        DecimalFormatSymbols symbols = format.getDecimalFormatSymbols();
        symbols.setCurrencySymbol("");
        format.setDecimalFormatSymbols(symbols);

        Label currencySignLabel = new Label(symbol);
        valueLabel = new Label();
        pane = new AnchorPane(currencySignLabel, valueLabel);
        AnchorPane.setLeftAnchor(currencySignLabel, 0.0);
        AnchorPane.setRightAnchor(valueLabel, 0.0);
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    }

    @Override
    protected void updateItem(Long price, boolean empty) {
        super.updateItem(price, empty);
        if (empty) {
            setGraphic(null);
        } else {
            // manual formatting 
            //String text = String.format("%,d.%02d", price / 100, Math.abs(price % 100));
            valueLabel.setText(format.format(price));
            setGraphic(pane);
        }
    }
}

这是一个 SSCCE:

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class TableViewWithAccountingStyleCell extends Application {

    public static class PriceTableCell<S> extends TableCell<S, Long> {

        private final AnchorPane pane ;
        private final Label valueLabel ;
        // locale-aware currency format to use for formatting
        private DecimalFormat format;

        public PriceTableCell() {
            // grab an instance
            format = (DecimalFormat) NumberFormat.getCurrencyInstance();
            //get the currency symbol
            String symbol = format.getCurrency().getSymbol();
            // replace the currency symbol with an empty string
            DecimalFormatSymbols symbols = format.getDecimalFormatSymbols();
            symbols.setCurrencySymbol("");
            format.setDecimalFormatSymbols(symbols);

            Label currencySignLabel = new Label(symbol);
            valueLabel = new Label();
            pane = new AnchorPane(currencySignLabel, valueLabel);
            AnchorPane.setLeftAnchor(currencySignLabel, 0.0);
            AnchorPane.setRightAnchor(valueLabel, 0.0);
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        @Override
        protected void updateItem(Long price, boolean empty) {
            super.updateItem(price, empty);
            if (empty) {
                setGraphic(null);
            } else {
                // manual formatting 
                //String text = String.format("%,d.%02d", price / 100, Math.abs(price % 100));
                valueLabel.setText(format.format(price));
                setGraphic(pane);
            }
        }
    }

    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final LongProperty price = new SimpleLongProperty();

        public Item(String name, long price) {
            setName(name);
            setPrice(price);
        }

        public StringProperty nameProperty() {
            return name ;
        }

        public final String getName() {
            return nameProperty().get();
        }

        public final void setName(String name) {
            nameProperty().set(name);
        }

        public LongProperty priceProperty() {
            return price ;
        }

        public final long getPrice() {
            return priceProperty().get();
        }

        public final void setPrice(long price) {
            priceProperty().set(price);
        }
    }

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>();
        table.getColumns().add(column("Item", Item::nameProperty));
        TableColumn<Item, Long> priceColumn = column("Price", item -> item.priceProperty().asObject());
        priceColumn.setPrefWidth(300);

        priceColumn.setCellFactory(tc -> new PriceTableCell<>());

        table.getColumns().add(priceColumn);


        Random rng = new Random();
        for (int i = 1 ; i <= 20 ; i++) {
            table.getItems().add(new Item("Item "+i, rng.nextInt(1_000_000)));
        }

        Scene scene = new Scene(table);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private <S,T> TableColumn<S,T> column(String name, Function<S, ObservableValue<T>> property) {
        TableColumn<S,T> column = new TableColumn<>(name);
        column.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return column ;
    }

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

产生

enter image description here

关于java - "Accounting"JavaFX 中的样式表单元格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48552499/

相关文章:

css - 获取 2 图像垂直对齐

css - 我怎样才能水平居中这个动画?

Java数组,int重置为0?

JavaFx 13 - TableView Vertical ScrollBar 处理程序返回 NullPointerException

java - 如何在 JavaFX 中的另一个 Controller 中使用类似(面板、anchorpane)的组件

JavaFX - 如何从主方法创建多个窗口?

c++ - GCC 中的结构成员对齐

java泛型方法警告 "Unchecked cast"

java - 一个字母一个字母地拼写

java - 如何用mock代替方法调用?