Javafx 自定义单元工厂节点不工作但在单元工厂中继承的 setText() 方法是

Javafx custom cell factory nodes not working but inherited setText() method in Cell factory is

我做了一个定制的细胞工厂。大多数值显示正确,但有些值显示不正确。当我扩展和折叠单元格时,问题变得更糟。奇怪的是继承的 setText() 方法按预期工作。我只是使用 setText() 方法来帮助我理解为什么这不起作用。您会注意到我自定义内容左侧的 setText() 方法的内容。

查看第一个单元格,您会注意到 none 的自定义单元格内容正在显示(最值得注意的是,TextFlow 节点未显示)。但是 setText() 内容确实如此,所以我知道 if 语句逻辑按预期工作。知道到底发生了什么吗?

下面是代码:

import java.util.Collections;
import java.util.List;

import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;

public class CellValueMaker extends TreeTableCell<ProviderAttribute, ProviderAttribute>{

    ImageView up;
    ImageView down;
    GridPane grid;
    Text cellName;
    Text cellDesc;
    Label serialNumber;
    VBox innerVB;
    GridPane innerLowerGrid;
    ImageButton upButton;
    ImageButton downButton;
    TextFlow flow;

    public CellValueMaker(){
        up = new ImageView(new Image(getClass().getResourceAsStream(
                "/resources/up.png")));
        up.setFitHeight(15);
        up.setFitWidth(15);
        upButton = new ImageButton(up);

        down = new ImageView(new Image(getClass().getResourceAsStream(
                "/resources/down.png")));
        down.setFitHeight(15);
        down.setFitWidth(15);
        downButton = new ImageButton(down);

        grid = new GridPane();
        innerVB = new VBox();
        innerVB.setPadding(new Insets(0, 0, 0, 3));
        innerLowerGrid = new GridPane();

        serialNumber = new Label("");
        serialNumber.setFont(Font.font ("System", 10));
        innerLowerGrid.add(serialNumber, 1, 0);
        cellName = new Text("");
        cellDesc = new Text("");
        cellDesc.setStyle("-fx-font-weight: bold");
        flow = new TextFlow();
        flow.getChildren().addAll(cellDesc, cellName);



        innerVB.getChildren().addAll(flow, serialNumber);

        upButton.setOnMouseClicked(new OnMoveUp());
        downButton.setOnMouseClicked(new OnMoveDown());

        // set lower nested grid
        grid.add(upButton, 0, 0);
        grid.add(downButton, 1, 0);
        grid.add(innerVB, 2, 0);
        setGraphic(grid);
    }

    @Override
    public void updateItem(ProviderAttribute item, boolean empty){
        super.updateItem(item, empty);

        if(item == null || empty){
            setGraphic(null);       
            setText("");
            setStyle("-fx-background-color: white;");
            cellName.setText("");
            cellDesc.setText("");
        }else{
            if(item instanceof DigitalIdentityType){
                DigitalIdentityType certBean = item.getEncapsulatedBean();
                setGraphic(grid);
                cellName.setText(item.getStringName());
                cellDesc.setText("Cert: ");
                setText(item.getStringName());
                setStyle("-fx-background-color: darkkhaki;");
                if(certBean.getParentCert() != null){
                    serialNumber.setText("SN: " + certBean.getParentCert().getSerialNumber().toString());
                }   
            }else if(item instanceof TSPServiceType){
                setGraphic(grid);
                cellName.setText(item.getStringName());
                serialNumber.setText("");
                cellDesc.setText("Service: ");
                setStyle("-fx-background-color: lightblue;");
                setText("Service: " + item.getStringName());
            }else if(item instanceof TSPType){
                setGraphic(grid);
                cellName.setText(item.getStringName());
                serialNumber.setText("");
                cellDesc.setText("TSP: ");
                setText("TSP: " + item.getStringName());
                setStyle("-fx-background-color: bisque;");
            }else{
                GridPane pane = new GridPane();
                pane.add(innerVB, 0, 0);
                setGraphic(pane);
                setText(item.getStringName());
                serialNumber.setText("");
                setStyle("-fx-background-color: white;");
//              cellName.setText(item.getStringName());
            }
        }

    }

    public class OnMoveUp implements EventHandler<MouseEvent>{
         private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";

        @SuppressWarnings("unchecked")
        @Override
        public void handle(MouseEvent event) {
            Button button = (Button)event.getSource();
            button.setStyle(STYLE_PRESSED);

            // get the table
            TreeTableView<ProviderAttribute> table = (TreeTableView<ProviderAttribute>)
                    button.getParent().getParent().getParent()
                    .getParent().getParent().getParent().getParent();

            // get the item
            TreeTableRow<ProviderAttribute> row = (TreeTableRow<ProviderAttribute>)
                    button.getParent().getParent().getParent();
            ProviderAttribute itemValue  = row.getItem();
            TreeItem<ProviderAttribute> item = row.getTreeItem();

            ObservableList<TreeItem<ProviderAttribute>> list = item.getParent().getChildren();

            if(item == null || list == null || list.size() <= 1) return;

            // swap the current item with the one above it
            int index = getIndexOf(list, itemValue);
            if(index > 0){
                Collections.swap(list, index, index-1);
                table.getSelectionModel().clearSelection();
            }
        }

    }

    public class OnMoveDown implements EventHandler<MouseEvent>{
         private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";

        @SuppressWarnings("unchecked")
        @Override
        public void handle(MouseEvent event) {
            Button button = (Button)event.getSource();
            button.getGraphic().setOpacity(50);
            button.setStyle(STYLE_PRESSED);

            // get the table
            TreeTableView<ProviderAttribute> table = (TreeTableView<ProviderAttribute>)
                    button.getParent().getParent().getParent()
                    .getParent().getParent().getParent().getParent();

            // get the item
            TreeTableRow<ProviderAttribute> row = (TreeTableRow<ProviderAttribute>)
                    button.getParent().getParent().getParent();
            ProviderAttribute itemValue  = row.getItem();
            TreeItem<ProviderAttribute> item = row.getTreeItem();

            ObservableList<TreeItem<ProviderAttribute>> list = item.getParent().getChildren();
            if(item == null || list == null || list.size() <= 1) return;

            int index = getIndexOf(list, itemValue);
            if(index < list.size() - 1){
                Collections.swap(list, index, index+1);
                table.getSelectionModel().clearSelection();
            }
        }

    }

    public int getIndexOf(List<TreeItem<ProviderAttribute>> items, ProviderAttribute bean){
        int index = -1;
        for(int i = 0; i < items.size(); i++){
            if(items.get(i).getValue().equals(bean))
                return i;
        }

        return index;
    }

    public class ImageButton extends Button {
    private final String STYLE_NORMAL = "-fx-background-color: transparent; -fx-padding: 2, 2, 2, 2;";

    public ImageButton(ImageView image) {
        setGraphic(image);
        setStyle(STYLE_NORMAL);


        setOnMouseReleased(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
               setStyle(STYLE_NORMAL);
//               setOpacity(0);
            }            
        });
    }

}

//  public class EventHandler
}

由于单元格被重复使用,有时您会使 innerVB 成为在最后一个 else 子句中创建的新 GridPane 的子节点;但是 innerVB 已经是另一个父节点的子节点(grid,并且可能还有先前在同一 else 子句的先前调用中创建的网格窗格)。这违反了场景图的规则(一个节点只能是一个父节点的子节点),并且可能会混淆布局,导致无法预测的显示。

你可能应该这样做

grid.getChildren().clear();

每次调用 updateItem(),然后

grid.addRow(0, upButton, downButton, innerVB);

grid.addRow(0, innerVB);

根据需要。