TableView ObservableList change row style - javafx

I need to change the color of the rows that have in column 6 the letter 'N', I have seen many examples but not with ObservableList and I need to do it this way.
In the 'FOR' I control the size of the table and in the 'IF' I check that all rows that contain the letter 'N' in column 6 change the entire row color.
#FXML private TableView<ObservableList> table;
for(int i = 0; i< table.getItems().size(); i++){
if(table.getItems().get(i).get(6).toString().equalsIgnoreCase("N")){
//table.get.get(i).setStyle("-fx-background-color: yellow"); //NOT FOUND
}
}

Use a row factory on the table:
public class MyControllerClass {
#FXML
private TableView<ObservableList<Object>> table ; // TODO: use a more appropriate type than Object
public void initialize() {
table.setRowFactory(tv -> new TableRow<ObservableList<Object>>() {
#Override
protected void updateItem(ObservableList<Object> row, boolean empty) {
super.updateItem(row, empty);
if (row != null && row.get(6).toString().equalsIgnoreCase("N")) {
setStyle("-fx-background-color: yellow;");
} else {
setStyle("");
}
}
});
}
// ...
}

Related

Edit JavaFx TableView cell with TextField in different columns

I have TableView which contain 3 columns, Two of them are edit with TextFields to permit user enter data into them but when I retrieve items from the table it return what is not into the TextFields like in image not return the correct numbers in the cells
Table with sample data
this is my code:
Edit I found that the problem in my ObservableList (data) I add action to the TextField to update data with new value but how to make code update different rows because it update the value with the last value in the TextField and get rid of to press ENTER to get the whole value in the TxtField because it ignore the last char for example if enter "30" in the TxtField I get "3" not "30"
productQuantity.setCellFactory(new Callback <TableColumn, TableCell> ()
{
#Override
public TableCell call(TableColumn param)
{
return new TableCell()
{
private TextField txtProductQuantity;
#Override
protected void updateItem(Object item, boolean empty)
{
super.updateItem(item, empty);
if(!empty)
{
setGraphic(getTextField());
}
else
{
setGraphic(null);
}
}
public TextField getTextField()
{
if(txtProductQuantity == null)
{
txtProductQuantity = new TextField();
txtProductQuantity.setAlignment(Pos.BASELINE_RIGHT);
txtPurchaseItemPrice.setOnKeyPressed(e ->
{
data.get(0).setPurchaseItemPrice(txtPurchaseItemPrice.getText());
});
}
return txtProductQuantity;
}
};
}
});
productQuantity.setOnEditCommit(new EventHandler<CellEditEvent<ProductOpeningBalance, String>> ()
{
#Override
public void handle(CellEditEvent<ProductOpeningBalance, String> t)
{
((ProductOpeningBalance)
t.getTableView().getItems().get(t.getTablePosition().getRow())
).setProductQuantity(t.getNewValue());
}
});
the code to retrieve data from the table
size = tableProductOpeningBalance.getItems().size();
for(int i = 0; i < size; i++)
{
System.out.println(tableProductOpeningBalance.getItems().get(i).getPurchaseItemPrice());
}
please help?

How can i color a specific row with specific condition in TableView?

I am using jfxml to create my tableview and use the Controller to action it .
in the Controller i want to make a specific row with a different color with specific action for my Cell it is TextFieldTableCell .
And this some code from action :
coldisc.setCellFactory(TextFieldTableCell.forTableColumn());
coldisc.setOnEditCommit(e -> {
e.getTableView().getItems().get(e.getTablePosition().getRow()).setDisc(e.getNewValue());
Brand b = tablebrand.getSelectionModel().getSelectedItem();
TablePosition pos2 = tablebrand.getFocusModel().getFocusedCell();
Calc();
CalcDisc();
//**********
Platform.runLater(() -> tablebrand.edit(pos2.getRow(), colafterdisc));
//**********
if (pos2.getRow() == tablebrand.getItems().size() - 1) {
tablebrand.getItems().add(new Brand("", "", "", "", "", "", ++ts));
}
Platform.runLater(() -> tablebrand.edit(pos2.getRow() + 1, colcode));
tablebrand.getSelectionModel().clearAndSelect(pos2.getRow() + 1, colcode);
final TablePosition pos3 = tablebrand.getFocusModel().getFocusedCell();
CalcTot();
}
});
One way of doing this is by conditionally adding a style class to the rows where needed:
final String styleClass = "color-class";
tableView.setRowFactory(new Callback<TableView<Foo>, TableRow<Foo>>() {
#Override
public TableRow<Foo> call(TableView<Foo> fooTableView) {
return new TableRow<Foo>() {
#Override
protected void updateItem(Foo foo, boolean empty) {
super.updateItem(foo, empty);
if (/* condition */) {
getStyleClass().add(styleClass);
} else { /* remove if condition no longer true */
getStyleClass().remove(styleClass);
}
}
};
}
});
Then in your css file, you can add the required color:
.table-row-cell.color-class {
-fx-background-color: /*your color*/;
}
This works using setStyle method.
If a specific condition is matched, then add : setStyle("your custom styling");
If not, just add setStyle("");
Let's figure out how it works, just imagine you want to highlight rows with null values :
// styling javafx tablerow with null values -> background color : red
Callback<TableView<T>, TableRow<T>> rowFactory = new Callback<TableView<T>, TableRow<T>>() {
#Override
public TableRow<T> call(TableView<T> l) {
return new TableRow<T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
try {
// isNull() is a custom method to catch null values in a row
if (isNull()) {
setStyle("-fx-background-color: #ff8080;");
} else {
// No empty cells - No specific highlights
setStyle("");
}
} catch (NullPointerException e) {
}
}
};
}
};
tv.setRowFactory(rowFactory);

Add buttons to the row currently being edited

I have tried searching both google and stackoverflow for answer to my question but I could not find any.
I have a program that adds/reads data from a database and to a tableview. I want to be able to edit the previously entered data from the tableview by adding two buttons (Save and abort) to the current row being edited.
I am having some troubles understanding the routines like Callback etc. But I have managed to get a column with two buttons to appear when I start the edit. But I get buttons on every column I just want the buttons on the currently
selected row. Also I don't really understand how to get the current object from the save-button to be able to save it.
And also how the abort-button should work to cancel all changes.
public void setUpTableView() {
columnAnkomstdatum.setCellValueFactory(new PropertyValueFactory<>("arrivalDate"));
columnSupplier.setCellValueFactory(new PropertyValueFactory<>("supplier"));
columnRadiopharmaceutical.setCellValueFactory(new PropertyValueFactory<>("radiopharmaceutical"));
columnActivity.setCellValueFactory(new PropertyValueFactory<>("startActivity"));
columnCalibrationdate.setCellValueFactory(new PropertyValueFactory<>("startDate"));
columnBatchNumber.setCellValueFactory(new PropertyValueFactory<>("batchNumber"));
columnContaminationControl.setCellValueFactory(new PropertyValueFactory<>("contaminationControll"));
columnRoom.setCellValueFactory(new PropertyValueFactory<>("room"));
columnUser.setCellValueFactory(new PropertyValueFactory<>("user"));
tableview.setEditable(true);
columnSupplier.setEditable(true);
columnSupplier.setCellFactory(ComboBoxTableCell.forTableColumn(supplierList));
columnSupplier.setOnEditCommit(t -> {
ArrayList<Radiopharmaceutical> radioListfromSupplier = new RadiopharmaceuticalDao().getRadiopharmaceuticalsBySupplierName(t.getNewValue().getSupplierName());
radioList = FXCollections.observableArrayList(radioListfromSupplier);
t.getRowValue().setSupplier(t.getNewValue());
columnRadiopharmaceutical.setCellFactory(ComboBoxTableCell.forTableColumn(radioList));
if(tableview.getColumns().size() <= 9) {
addButtonsToTable();
}
});
}
private void addButtonsToTable() {
TableColumn<RegRadio, Void> editRow = new TableColumn<>("Edit");
tableview.getColumns().add(editRow);
Callback<TableColumn<RegRadio, Void>, TableCell<RegRadio, Void>> cellFactory = new Callback<TableColumn<RegRadio,Void>, TableCell<RegRadio,Void>>() {
#Override
public TableCell<RegRadio, Void> call(final TableColumn<RegRadio, Void> param) {
final TableCell<RegRadio, Void> cell = new TableCell<RegRadio, Void>() {
private final Button btnSave = new Button("Save");
private final Button btnAbort = new Button("Avbryt");
{
btnSave.setOnAction((ActionEvent event) -> {
RegRadio rr = getTableView().getItems().get(getIndex());
System.out.println("Saved");
});
}
{
btnAbort.setOnAction((ActionEvent event) -> {
System.out.println("Abort");
});
}
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
HBox pane = new HBox(btnSave, btnAbort);
setGraphic(pane);
}
}
};
return cell;
}
};
editRow.setCellFactory(cellFactory);
tableview.getColumns().add(editRow);
}
In your updateItem callback you can check if the cell is in the selected row in order to decide if you should show the buttons or not. Additionally you also need a flag to check if the user is editing. Something like this:
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
var selectedCells = tableview.getSelectionModel().getSelectedCells();
if (empty || !isEditing || selectedCells.isEmpty || getTableRow().getIndex() != selectedCells.get(0).getRow()) {
setGraphic(null);
} else {
HBox pane = new HBox(btnSave, btnAbort);
setGraphic(pane);
}
}
Another approach would be to change the visibility of the buttons depending on whether the cell is in the selected row:
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
HBox pane = new HBox(btnSave, btnAbort);
var selectedCells = tableview.getSelectionModel().getSelectedCells();
pane.setVisible(!selectedCells.isEmpty() && getTableRow().getIndex() == selectedCells.get(0).getRow())
setGraphic(pane);
}
}
(I haven't compiled and tested these code samples)

Cell dependent appearance of cell in 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 ;).

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

Resources