You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX动态添加TableView行时数据重复显示问题求助

JavaFX TableView动态添加行后出现虚假重复行问题

问题描述

在JavaFX中实现TableView,点击按钮动态添加行后,原有数据出现视觉上的重复显示。排查确认数据源的实际条目数量正确,但这些重复行无法被选中、滚动查看或通过代码访问,属于虚假显示。

相关代码

detail.fxml

<TableView fx:id="tblPersonalExterno" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
    <columns>
        <TableColumn prefWidth="781.0000244379044">
            <graphic>
                <Label text="Externo" />
            </graphic>
            <columns>
                <TableColumn fx:id="tblcNombreExterno" prefWidth="270" text="Nombre"/>
                <TableColumn fx:id="tblcEmpresaExterno" prefWidth="270" text="Empresa" />
                <TableColumn fx:id="tblcInfPRLExterno" minWidth="0.0" prefWidth="59.0">
                    <graphic>
                        <Label text="Inf. PRL">
                            <tooltip>
                                <Tooltip text="Informado PRL" />
                            </tooltip>
                        </Label>
                    </graphic>
                </TableColumn>
                <TableColumn fx:id="tblcAprobadoPRLExterno" minWidth="0.0" prefWidth="73.00003051757812">
                    <graphic>
                        <Label text="Apr. Cl. PRL">
                            <tooltip>
                                <Tooltip text="Aprobado cliente PRL" />
                            </tooltip>
                        </Label>
                    </graphic>
                </TableColumn>
                <TableColumn fx:id="tblcFechaAprPRLExterno" prefWidth="100.0">
                    <graphic>
                        <Label text="Fecha apr.">
                            <tooltip>
                                <Tooltip text="Fecha de aprobación" />
                            </tooltip>
                        </Label>
                    </graphic>
                </TableColumn>
                <TableColumn prefWidth="60.0" text="Validez PRL">
                    <columns>
                        <TableColumn fx:id="tblcFechaDesdePRLExterno"  prefWidth="100.0" text="Desde" />
                        <TableColumn fx:id="tblcFechaHastaPRLExterno" prefWidth="100.0" text="Hasta" />
                    </columns>
                </TableColumn>
            </columns>
        </TableColumn>
    </columns>
</TableView>
<ToolBar prefHeight="40.0" prefWidth="200.0">
    <items>
        <Button fx:id="btnAñadirExterno" mnemonicParsing="false" onAction="#addExterno">
            <graphic>
                <FontIcon iconLiteral="mdi-account-plus"
                    iconSize="16" />
            </graphic>
            <tooltip>
                <Tooltip text="Añadir Personal Externo" />
            </tooltip>
        </Button>
        <Button fx:id="btnEliminarExterno" mnemonicParsing="false">
            <graphic>
                <FontIcon iconLiteral="mdi-delete-forever"
                    iconSize="16" />
            </graphic>
            <tooltip>
                <Tooltip text="Eliminar Personal Externo" />
            </tooltip>
        </Button>
    </items>
</ToolBar>

DetailsController.java

public class DetailsController {
    private ObservableList<Responsable> listaPersonalExterno = FXCollections.observableArrayList();
    @FXML
    private TableView<Responsable> tblPersonalExterno;
    @FXML
    private TableColumn<Responsable, String> tblcNombreExterno;
    @FXML
    private TableColumn<Responsable, String> tblcEmpresaExterno;
    @FXML
    private TableColumn<Responsable, Boolean> tblcInfPRLExterno;
    @FXML
    private TableColumn<Responsable, Boolean> tblcAprobadoPRLExterno;
    @FXML
    private TableColumn<Responsable, LocalDate> tblcFechaAprPRLExterno;
    @FXML
    private TableColumn<Responsable, LocalDate> tblcFechaDesdePRLExterno;
    @FXML
    private TableColumn<Responsable, LocalDate> tblcFechaHastaPRLExterno;
    
    public DetailsController() {
        cargarPersonalExterno();
    }
    public ObservableList<Responsable> listaPersonalExterno(){
        return listaPersonalExterno;
    }
    
    @FXML
    public void initialize() {
        doBindTablaPersonalExterno();
    }
    
    private void doBindTablaPersonalExterno() {
        tblcNombreExterno.setCellValueFactory(new PropertyValueFactory<Responsable, String>("nombre"));
        tblcNombreExterno.setCellFactory(col -> {
            TableCell<Responsable, String> cell = new TableCell<Responsable, String>(){
                @Override
                public void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        TextField tf = new TextField();
                        tf.setText(item);
                        setGraphic(tf);
                    }
                }
            };
            return cell;
        });
        tblcEmpresaExterno.setCellValueFactory(new PropertyValueFactory<Responsable, String>("empresa"));
        tblcEmpresaExterno.setCellFactory(col -> {
            TableCell<Responsable, String> cell = new TableCell<Responsable, String>(){
                @Override
                public void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        TextField tf = new TextField();
                        tf.setText(item);
                        setGraphic(tf);
                    }
                }
            };
            return cell;
        });
        tblcInfPRLExterno.setCellValueFactory(cellData -> new SimpleBooleanProperty(cellData.getValue().getPrl().isInformado()));
        tblcInfPRLExterno.setCellFactory(col -> {
            TableCell<Responsable, Boolean> cell = new TableCell<Responsable, Boolean>(){
                @Override
                public void updateItem(Boolean item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        CheckBox chk = new CheckBox();
                        setStyle("-fx-alignment: CENTER;");
                        if(item != null) {
                            chk.setSelected(item);
                        }
                        setGraphic(chk);
                    }
                }
            };
            return cell;
        });
        tblcAprobadoPRLExterno.setCellValueFactory(cellData -> new SimpleBooleanProperty(cellData.getValue().getPrl().isAprobado()));
        tblcAprobadoPRLExterno.setCellFactory(col -> {
            TableCell<Responsable, Boolean> cell = new TableCell<Responsable, Boolean>(){
                @Override
                public void updateItem(Boolean item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        CheckBox chk = new CheckBox();
                        setStyle("-fx-alignment: CENTER;");
                        if(item != null) {
                            chk.setSelected(item);
                        }
                        setGraphic(chk);
                    }
                }
            };
            return cell;
        });
        tblcFechaAprPRLExterno.setCellValueFactory(cellData -> new SimpleObjectProperty<LocalDate>(cellData.getValue().getPrl().getFechaAprobacion()));
        tblcFechaAprPRLExterno.setCellFactory(col -> {
            TableCell<Responsable, LocalDate> cell = new TableCell<Responsable, LocalDate>(){
                @Override
                public void updateItem(LocalDate item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        DatePicker dp = new DatePicker();
                        setStyle("-fx-alignment: CENTER;");
                        dp.setValue(item);
                        setGraphic(dp);
                    }
                }
            };
            return cell;
        });
        
        tblcFechaDesdePRLExterno.setCellValueFactory(cellData -> new SimpleObjectProperty<LocalDate>(cellData.getValue().getPrl().getValidez().getInicio()));
        tblcFechaDesdePRLExterno.setCellFactory(col -> {
            TableCell<Responsable, LocalDate> cell = new TableCell<Responsable, LocalDate>(){
                @Override
                public void updateItem(LocalDate item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        DatePicker dp = new DatePicker();
                        setStyle("-fx-alignment: CENTER;");
                        dp.setValue(item);
                        setGraphic(dp);
                    }
                }
            };
            return cell;
        });
        
        tblcFechaHastaPRLExterno.setCellValueFactory(cellData -> new SimpleObjectProperty<LocalDate>(cellData.getValue().getPrl().getValidez().getInicio()));
        tblcFechaHastaPRLExterno.setCellFactory(col -> {
            TableCell<Responsable, LocalDate> cell = new TableCell<Responsable, LocalDate>(){
                @Override
                public void updateItem(LocalDate item, boolean empty) {
                    super.updateItem(item, empty);
                    if(empty) {
                        setText("");
                    }else {
                        DatePicker dp = new DatePicker();
                        setStyle("-fx-alignment: CENTER;");
                        dp.setValue(item);
                        setGraphic(dp);
                    }
                }
            };
            return cell;
        });
    }
        
    /**
     * Carga el personal externo
     */
    private void cargarPersonalExterno() {
        List<Responsable> lista = new ArrayList<Responsable>();
        Responsable r1 = new Responsable();
        r1.setNombre("NEUS");
        Responsable r2 = new Responsable();
        r2.setNombre("PEPE");
        lista.add(r1);
        lista.add(r2);
        listaPersonalExterno.addAll(lista);
    }
        
    @FXML
    public void addExterno() {
        Responsable r = new Responsable();
        listaPersonalExterno.add(r);
    }
    
}

问题截图

虚假重复行显示
重复显示的行位于空白行下方,实际不存在且无法进行任何交互操作。


内容的提问来源于stack exchange,提问作者Nessarose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:05:52