JavaFX自定义CellFactory Wrapper抛出空指针

时间:2016-11-24 01:13:42

标签: java javafx

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

import React, {Component} from 'react';
import {render} from 'react-dom';
import {Router, Route, browserHistory, IndexRoute} from 'react-router';
//Import custom components
import About from '../components/about.js';
import Contact from '../components/contact.js';
import Sidebar from '../components/sidebar.js';
import Imagelist from '../components/image-list.js';


  render(
      <Router history={browserHistory}>
        <Route path="/" component={Sidebar}>
          <IndexRoute component={Imagelist}/>
          <Route path="/about" component={About}/>
          <Route path="/contact" component={Contact}/>
        </Route>
      </Router>,
      document.getElementById('content')
    );

这个cellfactory包装器通常可以浏览我的所有tableview。但是,只要我在系统中执行其他功能,例如添加新记录,编辑记录等,就会抛出以下错误。

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;
        }   
    }
}

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

1 个答案:

答案 0 :(得分:3)

在第一次调用TableCell方法时,无法保证TableRow已与TableRow关联,或updateItem已填充。{ / p>

在您的情况下,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();

确实是导致错误的行,那么导致这样的堆栈跟踪的唯一方法就是cmlnull

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

cml = (Cml) cell.getTableView().getItems().get(getIndex());