Cell dependent appearance of cell in JavaFX - javafx

How can I change the appearance of a cell based on the status of another cell in the same column of a tableView in JavaFX.
colHidden.setCellValueFactory(param -> {
return param.getValue().hiddenProperty();
});
colHidden.setCellFactory(tc -> new CheckBoxTableCell<>());
colLabel.setCellFactory(...);
I have a cell which contains CheckBoxTableCell<>(). When I select this checkbox the content of the cell colLabel should be replaced by asterisks.

You can do something like this. The basic idea here is to "remember" the property corresponding to the check box in the same row, assuming the cell is not empty, and add a listener to it that updates the text. Then remove the listener from the previous property whenever the cell updates.
colLabel.setCellFactory(col -> new TableCell<RowType, ColumnType>() {
private ObservableValue<Boolean> hiddenProperty ;
ChangeListener<Boolean> listener = (obs, wasHidden, isNowHidden) -> updateText(isNowHidden);
#Override
protected void updateItem(ColumnType item, boolean empty) {
super.updateItem(item, empty);
if (hiddenProperty != null) {
hiddenProperty.removeListener(listener);
}
if (empty) {
setText(null);
hiddenProperty = null ;
} else {
hiddenProperty = getTableView().getItems().get(getIndex()).hiddenProperty();
hiddenProperty.addListener(listener);
updateText(hiddenProperty.get());
}
}
private void updateText(boolean hidden) {
if (hidden) {
setText("********");
} else {
setText(getItem().toString()); // or other format for string, etc
}
}
}
Replace RowType and ColumnType with the actual types used by colLabel (i.e. this assumes you have TableColumn<RowType, ColumnType> colLabel ;).

Related

How to modify the selected tableview according to the tableview cell

I have customized a Hyperlink cell here. I want the tableview to select the content when I click this link, but after I add Hyperlink, the tableview's selected seems to be invalid.
tb_uGoodUrl.setCellFactory(new Callback<TableColumn<GoodModel, String>, TableCell<GoodModel, String>>() {
#Override
public TableCell<GoodModel, String> call(TableColumn<GoodModel, String> param) {
TableCell<GoodModel, String> cell = new TableCell<GoodModel, String>() {
private final Hyperlink hyperlink = new Hyperlink();
{
hyperlink.setOnMouseClicked(event -> {
if(event.getClickCount() == 2){
String url = getItem();
hostServices.showDocument(url);
}
});
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
}else {
hyperlink.setText(getItem());
setGraphic(hyperlink);
}
}
};
return cell;
}
});
Click on the link, the cell is not selected
If the cell is not selected, a null exception will be reported when the following code is used.
TablePosition pos = tableView.getSelectionModel().getSelectedCells().get(0);
int row = pos.getRow();
// Item here is the table view type:
GoodModel item = tableView.getItems().get(row);
TableColumn col = pos.getTableColumn();
// this gives the value in the selected cell:
String data = (String) col.getCellObservableValue(item).getValue();
The effect you want to achieve is as follows
Rendering
You can manually select the cell, using the table's selection model, when the Hyperlink is clicked on.
// Assuming this code is inside a TableCell implementation
hyperlink.setOnAction(event -> {
event.consume();
getTableView().getSelectionModel().select(getIndex(), getTableColumn());
// show your document
});
I used the onAction property which will be fired when the Hyperlink has been clicked once. This is typical behavior for a hyperlink, but if you want to only perform the action on a double-click then you can keep using your onMouseClicked handler.
Note the above does not take into account multiple-selection mode.

JavaFX TableView custom row style on double click

I have a TableView in my JavaFX application.
I would like to style differently row when it is double-clicked on it, and differently when it is single-clicked.
Here is what I achieve:
final PseudoClass doubleClickPseudoClass = PseudoClass.getPseudoClass("new");
setRowFactory(tableView -> {
final TableRow<Bean> row = new TableRow<Bean>();
row.setOnMouseClicked(event -> {
if (event.getClickCount() == 2 && (! row.isEmpty())) {
row.pseudoClassStateChanged(doubleClickPseudoClass, true);
});
return row;
});
However, when the user doubles click on every new row, I want all previously double-clicked rows to be styled without applying "new" class:
row.pseudoClassStateChanged(doubleClickPseudoClass, false);
How can I do that?
Now I have cumulative styled all rows as they are double-clicked.
You shouldn't use TableRows to store the state themselves since new items may be assigned to a TableRow instance. Instead use a property to store the item double-clicked item and use a listener for styling the rows:
final ObjectProperty<Bean> doubleClickedObject = new SimpleObjectProperty<>();
setRowFactory(tableView -> new TableRow<Bean>() {
private void updateStyle() {
pseudoClassStateChanged(doubleClickPseudoClass, !isEmpty() && doubleClickedObject.get() == getItem());
}
private final InvalidationListener listener;
{
listener = o -> updateStyle();
doubleClickedObject.addListener(new WeakInvalidationListener(listener));
setOnMouseClicked(event -> {
if (!isEmpty() && event.getClickCount() == 2) {
doubleClickedObject.set(getItem());
}
});
}
#Override
protected void updateItem(Bean item, boolean empty) {
super.updateItem(item, empty);
updateStyle();
}
});

JavaFX : color individual TreeItems using css

I want to be able to color individual Tree Item of treeView based on some condition.
This answer seems good but I am unable to implement it.
https://stackoverflow.com/a/10931896/6653207
I am unable to understand how to use setCellFactory method to format individual TreeItems.
I have a class
public class Bag {
public String caption,assignment="";
Boolean eval;
public Set<Vertex> Nodes = new HashSet<Vertex>();
public Vector<Bag> ChildBags = new Vector<Bag>();
#Override
public String toString()
{
return assignment+ " " +caption;
}
}
Here's my css file:
.true{
-fx-text-fill:#33cc00 ;
}
.assignment{
-fx-text-fill: #0033cc
}
So I want to color to green the caption ( the toString() method returns ) of all those nodes whose eval property is true.
and assignment string which toString() method returns for all the nodes should be blue.
How can I do so?
Thanks.
By overriding the updateItem method of the TreeCell, you can adjust the TreeCell's properties based on the value of the TreeItem the cell contains.
In the following example a pseudoclass is assigned to all cells that contain a value with the prefix "child" and all empty cells get a black background.
TreeView<String> treeView = ...
PseudoClass childPseudoClass = PseudoClass.getPseudoClass("child");
treeView.setCellFactory(tv -> new TreeCell<String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
// update for empty cell / cell containing null
pseudoClassStateChanged(childPseudoClass, false);
setText("");
setStyle("-fx-background-color: black;");
} else {
// update for filled cell
pseudoClassStateChanged(childPseudoClass, item.startsWith("child"));
setText(item);
setStyle(null);
}
}
});
CSS Stylesheet
.tree-cell:child {
-fx-background-color: red;
}
The updateItem method is called by the TreeView every time the value changes, e.g. if a new TreeItem is associated with the cell or the value property of a TreeItem is modified.
You could also use the factory to add listeners to the TreeCell, before it's returned, in case you prefer this and e.g. want to change the cell based on the treeItem property.
EDIT: To apply different colors to the text, you need to use different Nodes for the text parts.
treeView.setCellFactory(tv -> new TreeCell<Bag>() {
private final Text assignment;
private final Text caption;
private final Node graphic;
{
assignment = new Text();
caption = new Text();
assignment.getStyleClass().add("assignment");
graphic = new HBox(4, assignment, caption);
setGraphic(graphic);
}
#Override
protected void updateItem(Bag item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
setGraphic(graphic);
assignment.setText(item.assignment);
caption.setText(item.caption);
caption.getStyleClass().remove("true");
if (item.eval) {
caption.getStyleClass().add("true");
}
}
}
});
To color the text you need to use the -fx-fill property instead of the -fx-text-fill property.

Colouring table row in JavaFX

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).

JavaFX8 Style not immediately updating

I am trying to change the color of the table rows when I set a boolean.
So I have this code:
boolean searchmode = false;
....
columns.forEach(c -> c.setCellFactory(column -> {
return new TableCell<ShowableInWarenkorb, String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : item);
if (searchmode) {
getStyleClass().add("searchmode");
} else{
getStyleClass().remove("searchmode");
}
}
};
}));
This CSS:
.searchmode {
-fx-background-color: rgba(153,153,153,0.3);
})
And then I switch searchmode eventually in my code before I am updating the table contents.
But the color does not change immediatley, sometimes I have to click a little bit around before it changes, how can I trigger it manually?
From your code, it looks like you want to apply this to all cells in the table. You can do this without a cell factory at all (though you may need one for other purposes).
Do
PseudoClass searchmodePseudoClass = PseudoClass.getPseudoClass("searchmode");
and then when you change the value of searchmode, do
table.pseudoClassStateChanged(searchmode);
In your css, do
.table-view:searchmode .table-cell {
-fx-background-color: rgba(153,153,153,0.3);
}
If you want to "automate" the update to the pseudoclass state, use a boolean property and add a listener:
private final BooleanProperty searchmode = new SimpleBooleanProperty(false);
public final boolean isSearchmode() {
return searchmodeProperty().get();
}
public final void setSearchmode(boolean searchmode) {
searchmodeProperty().set(searchmode);
}
public BooleanProperty searchmodeProperty() {
return searchmode ;
}
Then if you add the listener
searchmode.addListener((obs, wasSearchmode, isNowSearchmode) ->
table.pseudoClassStateChanged(searchmodePseudoClass, isNowSearchmode));
everything will be wired automatically so the table changes whenever you call setSearchmode(...).

Resources