问题描述
我创建了一个单元工厂包装器,以启用JavaFX表单元的自定义配置。请参阅下面的代码。
I have created a cell factory wrapper to enable custom configuration of a JavaFX table cell. See code below.
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包装器可以工作通常浏览我的所有tableviews。但是,只要我在系统中执行其他功能,例如添加新记录,编辑记录等,就会抛出以下错误。
And this cellfactory wrapper will work on generally navigating through all of my tableviews. However, as soon as I perform another function in my system such as adding new records, editing records etc. The following error is thrown.
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异常的想法?
I cant seem to figure out why this wrapper thinks that my CML class has null values in it. Anyone have any ideas as to why this Null Pointer exception is being thrown?
推荐答案
无法保证 TableCell
已经与 TableRow
相关联,或者 TableRow
已经填写第一次调用 updateItem
方法。
There is no guarantee that the TableCell
is already associated with a TableRow
or that the TableRow
is already filled when the updateItem
method is called the first time.
在你的情况下可能是 getTableRow()
返回 null
(但这意味着 cml =(Cml)cell.getTableRow()。getItem();
是抛出异常的行,而不是字符串SQLString =UPDATE IDMAS.CML SET CMLSTATUS ='< NEW_STATUS>'WHERE EQUIPMENT_ID ='+ cml.getEquipmentId()+ 'AND CML_NO =+ cml.getCmlNo();
);至少在我尝试重现错误时发生了这种情况。
In your case probably getTableRow()
returns null
(which would mean however that cml = (Cml) cell.getTableRow().getItem();
is the line the exception is thrown, not String SQLString = "UPDATE IDMAS.CML SET CMLSTATUS = '<NEW_STATUS>' WHERE EQUIPMENT_ID = '" + cml.getEquipmentId() + "' AND CML_NO = " + cml.getCmlNo();
); At least that happened when I tried to reproduce the error.
但是如果
String SQLString = "UPDATE IDMAS.CML SET CMLSTATUS = '<NEW_STATUS>' WHERE EQUIPMENT_ID = '" + cml.getEquipmentId() + "' AND CML_NO = " + cml.getCmlNo();
确实是导致错误的行,然后是导致堆栈跟踪的唯一方法像这样是 cml
是 null
。
is indeed the line causing the error, then the only way for that to happen that results in a stacktrace like this is if cml
is null
.
A修复此问题的方法是根据索引从表中获取项目:
A way to fix this would be getting the item from the table based on the index:
cml = (Cml) cell.getTableView().getItems().get(getIndex());
这篇关于JavaFX自定义CellFactory包装器抛出空指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!