I found a good example on the Internet how to do this, in fact it does not work. Below is the code with my comments, please help to figure out what's what and why it doesn't work.
#FXML
private void initialize() {
timeContractColumn.setCellFactory(column -> {
return new TableCell<MainData, LocalDate>() { // MainData - model,
// where all variables and collections for storing data are stored
// timeContractColumn - stores the entered date, therefore, LocalDate
#Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) { //If the cell is empty
setText(null);
setStyle("");
} else { //If the cell is not empty
setText(item.toString()); //We place the data in the cell
System.out.println(item);
// We get here all the information about this line.
MainData auxPerson = getTableView().getItems().get(getIndex());
System.out.println(auxPerson.toString());
// Change the style if ...
if (auxPerson.getTimeContract().equals("2019-04-09")) {
setTextFill(Color.RED);
setStyle("-fx-background-color: yellow");
} else {
//Here we see whether the row of this cell is highlighted or not
if(getTableView().getSelectionModel().getSelectedItems().contains(auxPerson))
setTextFill(Color.WHITE);
else
setTextFill(Color.BLACK);
}
}
}
};
});
}
Fabian was right, I did not take into account that I was comparing different objects, thanks for all the advice.
if (auxPerson.getTimeContract().toString().equals("2019-04-11"))
Related
I have got a problem with my cellFactory.
I want that if a Date is set to my object inside a FX TableView, that the updateItem method checks if it is a valid date. If not the cell should be colored red.
_availableCol.setCellFactory(column -> {
return new TableCell<SimpleReservationUnit, LocalDate>() {
#Override
protected void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
if (empty || date == null) {
setText(null);
}else {
if (date.compareTo(_newDeparture.getValue()) < 0) {
setStyle("-fx-background-color: red");
}else{
setStyle("");
}
}
}
};
});
The coloring works, but the LocalDate is never set to the cell. As far as I understand this should happen in the super() call.
A CellValueFactory is implemeted for this column:
_availableCol.setCellValueFactory(new PropertyValueFactory<>("Available"));
Any ideas what i am doing wrong?
You need to set the text of the node. You do clear it when you detect it is empty, but you don't set it when it is not. You also forget to clear the style if the cell is empty.
if (empty || date == null) {
setText(null);
setStyle(""); // can this be null?
} else {
LocalDate departureDate = _newDeparture.getValue();
String text = departureDate.toString(); // or format it for user locale
setText(text);
String style = date.isBefore(departureDate) ? "-fx-background-color: red" : "";
setStyle(style);
}
I have this problem with the first Hyperlink being alignment on top of TableCell.
I have tried almost everything and I could not get it to work.
colData.setCellFactory(e -> {
return new TableCell<TabelaShitjet, Hyperlink>(){
#Override
protected void updateItem(Hyperlink item, boolean empty) {
super.updateItem(item, empty);
if (!empty){
item.setOnAction(e -> {
TeDhenatBlerjes(Integer.parseInt(getTableView().getColumns().get(0).getCellData(getTableRow().getIndex())+""), item.getText());
});
setGraphic(item);
}
}
};
});
CONSTRUCTOR
public class TabelaShitjet {
private Hyperlink data;
public TabelaShitjet(String data){
this.data = new Hyperlink(data);
}
public Hyperlink getData() {
return data;
}
public void setData(Hyperlink data) {
this.data = data;
}
}
I've got no idea why exactly this happens, but if you remove the graphic when cell becomes empty by setting it to null, the problem seems to be fixed.
You should undo any modifications done to a cell when a item is added on a call of updateItem where the cell becomes empty anyway, since otherwise empty cells could be shown as if they were non-empty:
#Override
protected void updateItem(Hyperlink item, boolean empty) {
super.updateItem(item, empty);
if (!empty){
item.setOnAction(e -> {
TeDhenatBlerjes(Integer.parseInt(getTableView().getColumns().get(0).getCellData(getTableRow().getIndex())+""), item.getText());
});
}
// set graphic every time i.e. set it to null for empty cells
setGraphic(item);
}
In general the updateItem method should be implemented like this:
#Override
protected void updateItem(ItemType item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
// undo any updates that could have been made
// to make the cell look different from the empty cell
} else {
// update cell to display item
}
}
There TreeView, each element of which implements Viewable interface:
public interface Viewable {
enum ViewStyle {
NEW("-fx-background-color: b8faa7;"),
NEW_PARENT("-fx-background-color: b8ebbb;"),
LOCKED("-fx-background-color: adadad; "),
HAS_NO_DATA("-fx-background-color: eb8d8d;");
String style;
ViewStyle(String style){
this.style = style;
}
public String getStyle() {
return style;
}
}
ViewStyle getViewStyle();
void setViewStyle(ViewStyle style);
StringProperty styleProperty();
String getTreeItemTitle();
void setTreeItemTitle(String title);
StringProperty titleProperty();
}
Each element has its own .styleProperty(), and get value from ViewStyle.getStyle()
This property bind for each TreeCell.styleProperty():
treeView.setCellFactory(new Callback<TreeView<Viewable>, TreeCell<Viewable>>() {
#Override
public TreeCell<Viewable> call(TreeView<Viewable> param) {
return new TreeCell<Viewable>() {
#Override
protected void updateItem(Viewable item, boolean empty) {
textProperty().unbind();
styleProperty().unbind();
if (empty || item == null) {
setGraphic(null);
textProperty().set(null);
styleProperty().set(null);
return;
}
if (item != null) {
styleProperty().bind(item.styleProperty());
textProperty().bind(item.titleProperty());
}
super.updateItem(item, empty);
}
};
}
});
The problem is that tree cells are displayed ugly in the selection. That is the color of the selected cell does not change. Changing only the color of the letters (in accordance with the default theme), but it is not very convenient. Therefore, probably it is necessary to attach .css files. At the same time, I don't understand how to change the style (default and when selected) of the cell depending on the current ViewStyle.
You could simply change the css property to one that is only used for unselected cells (-fx-control-inner-background):
enum ViewStyle {
NEW("-fx-control-inner-background: b8faa7;"),
NEW_PARENT("-fx-control-inner-background: b8ebbb;"),
LOCKED("-fx-control-inner-background: adadad; "),
HAS_NO_DATA("-fx-control-inner-background: eb8d8d;");
Also note that you did something you shouldn't do in a overwritten version of the updateItem method: Not always call super.updateItem. This can lead to the filled/empty pseudoclasses not being assigned correctly and the item property of the TreeCell not containing the item from the latest updateItem call. You should do something like this instead:
#Override
protected void updateItem(Viewable item, boolean empty) {
textProperty().unbind();
styleProperty().unbind();
if (empty || item == null) {
setText(null);
setStyle(null);
} else {
styleProperty().bind(item.styleProperty());
textProperty().bind(item.titleProperty());
}
super.updateItem(item, empty);
}
This question is related to this. Now I want to colour the row where field value equals to some value.
#FXML
private TableView<FaDeal> tv_mm_view;
#FXML
private TableColumn<FaDeal, String> tc_inst;
tc_inst.setCellValueFactory(cellData -> new SimpleStringProperty(""+cellData.getValue().getInstrumentId()));
tc_inst.setCellFactory(column -> new TableCell<FaDeal, String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
setText(item);
// Style row where balance < 0 with a different color.
TableRow currentRow = getTableRow();
if (item.equals("1070")) {
currentRow.setStyle("-fx-background-color: tomato;");
} else currentRow.setStyle("");
}
}
});
The problem is I don't want to show tc_inst in my table. For this reason I set visible checkbox in SceneBuilder to false. In this case colouring part doesn't work at all. How can hide tc_inst so that colouring works?
Use a row factory, instead of a cell factory, if you want to change the color of the whole row:
tv_mm_view.setRowFactory(tv -> new TableRow<FaDeal>() {
#Override
public void updateItem(FaDeal item, boolean empty) {
super.updateItem(item, empty) ;
if (item == null) {
setStyle("");
} else if (item.getInstrumentId().equals("1070")) {
setStyle("-fx-background-color: tomato;");
} else {
setStyle("");
}
}
});
Note that if the value of instrumentId changes while the row is displayed, then the color will not change automatically with the above code, unless you do some additional work. The simplest way to make that happen would be to construct your items list with an extractor which returned the instrumentIdProperty() (assuming you are using the JavaFX property pattern in FaDeal).
I have a ComboBox which I'm populating with Sheet object values.
I set a Cell Factory in order to display the sheet's name in the drop down list itself. It works properly (seems so).
The problem is that after an item ("Cell") is selected, the value that is shown in the box is not the value that was shown in the list.
This is the relevant code part:
excelFile = new ExcelFile(file);
//ObservableList<String> sheets = FXCollections.observableArrayList(excelFile.getSheetsNames());
ObservableList<Sheet> sheets = FXCollections.observableArrayList(excelFile.getSheets());
sheetsBox.setItems(sheets);
sheetsBox.setDisable(false);
sheetsBox.setCellFactory(new Callback<ListView<Sheet>, ListCell<Sheet>>() {
#Override
public ListCell<Sheet> call(ListView<Sheet> param) {
return new ListCell<Sheet>() {
#Override
protected void updateItem(Sheet item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setText(item.getSheetName());
}
}
};
}
});
This is the problem (visually):
Thank you
The cell used to display the selected item is the buttonCell. So you just need to set the same cell for the button cell. You can factor the cell creation into a method to avoid replicating code:
sheetsBox.setCellFactory(lv -> createSheetCell());
sheetsBox.setButtonCell(createSheetCell());
// ...
private ListCell<Sheet> createSheetCell() {
return new ListCell<Sheet>() {
#Override
protected void updateItem(Sheet item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setText(item.getSheetName());
}
}
};
}