小编典典

JavaFX自定义CellFactory包装器抛出空指针

java

我创建了一个单元工厂包装器,以启用JavaFX表单元的自定义配置。请参见下面的代码。

package idmas.controller.modules.tableview;

import idmas.model.Cml;
import idmas.model.CmlDAO;
import idmas.model.Damageloop;
import idmas.model.modules.general.dateMethods;
import java.util.Date;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

/**
 * Generic cell factory that can be used to override specific properties of cells, such as formatting (text size, color etc.) and even values.
 * @author Joshua Adams
 * @param <S> = Data type of table view to be modified. E.g. Damageloop, Equipment, CML, Inspection etc.
 * @param <T> = Data type of specific cell being overridden. E.g. Date, Integer, Double etc.
 */
public class CellFactoryCustom<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>>  {

    //Represents the name of the column for the specific tableview, i.e. Last Internal Inspection Date etc.
    String colname;

    //Constructors for class wide objects
    CmlDAO cmldao = new CmlDAO();

    /**
     * Class constructor requires a column name to be passed so the specific formatting for that column's cells can be applied.
     * @param colname = Name of column to apply formatting to.
     */
    public CellFactoryCustom (String colname) {
        this.colname = colname;
    }

    /**
     * Main method to override the properties of the cells for a table column.
     * @param arg
     * @return 
     */
    @Override
    public TableCell<S, T> call(TableColumn<S, T> arg) {
        TableCell<S, T> cell = new TableCell<S, T>() {
            @Override
            protected void updateItem(T item, boolean empty) {
                //super allows reffering to methods in superclass
                super.updateItem(item, empty);
                //recommended syntax for overridding the updateItem method - Refer to update item javadoc.
                if (empty || item == null) {
                    setText(null);
                    setGraphic(null);
                    getStyleClass().removeAll("highlightCellBlack");
                    getStyleClass().add(getTableRow().getStyleClass().toString());
                } else {
                    setConditionalFormatting(this,item);
                }
            }
        };
        return cell;
    }

    /**
     * Specific formatting rules which are applied to a columns cells based on its column name.
     * @param cell
     * @param item 
     */
    public void setConditionalFormatting (TableCell<S,T> cell, T item) {
        //Constructors for reference classes
        dateMethods datemethods = new dateMethods();
        Date currentdateplus60 = new Date();
        Date date;
        Damageloop damageloop;
        Cml cml;
        ComboBox combobox;
        //Current styles need to be removed to ensure all specific styles for each cell are applied correctly
        cell.getStyleClass().removeAll("highlightCellBlack");
        //Switch statement selected over if statement to improve performance of code and readibility
        switch (colname) {
            case "colNextExternalInspectionDate":
                damageloop = (Damageloop) cell.getTableRow().getItem();
                cell.setText(datemethods.getDateToString((Date) item,"dd/MM/yyyy"));
                currentdateplus60 = datemethods.getDatePlusDays(currentdateplus60, 60);
                date = (Date) item;
                if(date.before(currentdateplus60) && damageloop.getErrorcode() != 2 & damageloop.getErrorcode() != 3) {
                    cell.getStyleClass().add("highlightCellBlack");
                } else {
                    cell.getStyleClass().add(cell.getTableRow().getStyleClass().toString());
                }
                break;
            case "colNextInternalInspectionDate":
                damageloop = (Damageloop) cell.getTableRow().getItem();
                cell.setText(datemethods.getDateToString((Date) item,"dd/MM/yyyy"));
                currentdateplus60 = datemethods.getDatePlusDays(currentdateplus60, 60);
                date = (Date) item;
                if(date.before(currentdateplus60) && damageloop.getErrorcode() != 1 && damageloop.getErrorcode() != 3) {
                    cell.getStyleClass().add("highlightCellBlack");
                } else {
                    cell.getStyleClass().add(cell.getTableRow().getStyleClass().toString());
                }
                break;
            case "colCmlStatus":
                cml = (Cml) cell.getTableRow().getItem();
                String[] fieldsArray = new String[]{"C = Continue to Monitor", "S = Scoped", "X = Redundant"};
                String[] disabledFieldsArray = new String[]{"S = Scoped"};
                String SQLString = "UPDATE IDMAS.CML SET CMLSTATUS = '<NEW_STATUS>' WHERE EQUIPMENT_ID = '" + cml.getEquipmentId() + "' AND CML_NO = " + cml.getCmlNo();
                String replacestring = "<NEW_STATUS>";
                String defaultvalue = item.toString();
                ComboBoxCustom comboboxcustom = new ComboBoxCustom (fieldsArray, disabledFieldsArray, SQLString, replacestring, defaultvalue);
                comboboxcustom.setPrefWidth(10);
                cell.setGraphic(comboboxcustom);
                break;
            case "colCmlStatusRemediation":
                ObservableList<String> options = FXCollections.observableArrayList(
                        "A = Approved for Remediation",
                        "C = Continue to Monitor",
                        "F = Fit for Service",
                        "R = Recommend Remediation"
                );     
                cml = (Cml) cell.getTableRow().getItem();
                combobox = new ComboBox(options);
                combobox.setValue(item.toString());
                combobox.setPrefWidth(10);
                combobox.valueProperty().addListener(new ChangeListener<String>() {
                    @Override 
                    public void changed(ObservableValue ov, String oldvalue, String newvalue) {
                        cml.setCmlstatusremediation(newvalue.charAt(0));
                        cmldao.updateCml(cml);
                        //Platform runlater required to update the combox with the new value
                        Platform.runLater(() -> {
                            combobox.setValue(String.valueOf(newvalue.charAt(0)));
                        });
                    }    
                });
                cell.setGraphic(combobox);
                break;
            case "colTemporaryrepairinstalled":
                cml = (Cml) cell.getTableRow().getItem();
                CheckBox checkbox = new CheckBox();
                checkbox.setSelected(Boolean.valueOf(item.toString()));
                checkbox.selectedProperty().addListener(new ChangeListener<Boolean>() {
                    @Override
                    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                        cml.setTemporaryrepairinstalled(newValue);
                        cmldao.updateCml(cml);
                        checkbox.setSelected(newValue);
                    }
                });
                cell.setGraphic(checkbox);
                break;
            default:
                break;
        }   
    }
}

这个cellfactory包装器通常可以在我所有的表视图中导航。但是,一旦我在系统中执行其他功能,例如添加新记录,编辑记录等,就会引发以下错误。

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at idmas.controller.modules.tableview.CellFactoryCustom.setConditionalFormatting(CellFactoryCustom.java:110)
    at idmas.controller.modules.tableview.CellFactoryCustom$1.updateItem(CellFactoryCustom.java:60)
    at javafx.scene.control.TableCell.updateItem(TableCell.java:663)
    at javafx.scene.control.TableCell.indexChanged(TableCell.java:468)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.requestCellUpdate(TableRowSkinBase.java:659)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.handleControlPropertyChanged(TableRowSkinBase.java:234)
    at com.sun.javafx.scene.control.skin.TableRowSkin.handleControlPropertyChanged(TableRowSkin.java:70)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
    at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
    at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:72)
    at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:115)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1957)
    at com.sun.javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:1344)
    at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1197)
    at javafx.scene.Parent.layout(Parent.java:1087)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Scene.doLayoutPass(Scene.java:552)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)

我似乎无法弄清楚为什么这个包装器认为我的CML类中包含空值。任何人对于为什么会抛出此Null Pointer异常有任何想法?


阅读 180

收藏
2020-11-30

共1个答案

小编典典

不能保证在第一次调用该方法时,该TableCell变量已经与a关联TableRowTableRow已经被填充updateItem

在您的情况下,可能会getTableRow()返回null(但这意味着cml = (Cml) cell.getTableRow().getItem();抛出异常的那一行,而不是String SQLString = "UPDATE IDMAS.CML SET CMLSTATUS = '<NEW_STATUS>' WHERE EQUIPMENT_ID = '" + cml.getEquipmentId() + "' AND CML_NO = " + cml.getCmlNo(););至少在我尝试重现该错误时发生了。

但是如果

String SQLString = "UPDATE IDMAS.CML SET CMLSTATUS = '<NEW_STATUS>' WHERE EQUIPMENT_ID = '" + cml.getEquipmentId() + "' AND CML_NO = " + cml.getCmlNo();

确实是导致错误的行,那么导致这种情况的唯一方法就是if cmlis null

解决此问题的一种方法是根据索引从表中获取项目:

cml = (Cml) cell.getTableView().getItems().get(getIndex());
2020-11-30