I need to center the values displayed inside columns of a treetableview, how Can i change the position from left to center?
final TreeTableColumn<RootMaster, Integer> dataColumn = new TreeTableColumn<>("Data");
dataColumn.setEditable(false);
dataColumn.setMinWidth(300);
dataColumn.setCellValueFactory(new TreeItemPropertyValueFactory<RootMaster, Integer>("bu..."));
You need to set a cellFactory on the TreeTableColumn (as well as the cellValueFactory).
dataColumn.setCellFactory(col -> {
TreeTableCell<RootMaster, Integer> cell = new TreeTableCell<RootMaster, Integer>() {
#Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
setText(item.toString());
}
}
};
cell.setAlignment(Pos.CENTER);
return cell ;
});
Related
Currently I use a listener to wrap text on a tablecell but that causes a little delay when load/reload data table. Are there any other way to do this without use a listener?
TableColumn<Peticion, Void> colObs = new TableColumn<>("Observaciones");
colObs.setPrefWidth(200);
colObs.getStyleClass().add("columData");
colObs.setCellFactory(col->{
TableCell<Peticion, Void> cell = new TableCell<Peticion, Void>(){
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
Peticion p = getTableView().getItems().get(getIndex());
Label l = new Label(p.getObservaciones());
l.setWrapText(true);
VBox box = new VBox(l);
l.heightProperty().addListener((observable,oldValue,newValue)-> {
box.setPrefHeight(newValue.doubleValue()+7);
Platform.runLater(()->this.getTableRow().requestLayout());
});
super.setGraphic(box);
}
}
};
return cell;
});
I need your help!
I've got a Table with rows in it (Name, etc..)
Now, I want to color a specific tableCells background when the Object, laying on this row has got a specific value. But i only get it to read the value of this cell. But i need to read the Object (in my code called TableListObject) to know in wich color i need to color the cell. But this "color value" is not visible (has no column) in that row.
Here is my code:
for(TableColumn tc:tView.getColumns()) {
if(tc.getId().equals("text")) {
tc.setCellValueFactory(newPropertyValueFactory<TableListObject,String>("text"));
// here i need to check the Objects value and coloring that cell
}
}
Here is a HTML Fiddle to visualize my problem:
https://jsfiddle.net/02ho4p6e/
Call the cell factory for the column you want and override the updateItem method. You need to check if it is empty and then if it is not you can do your object check and then you can set the color of the cell background or any other style you want. Hope this helps.
tc.setCellFactory(column -> {
return new TableCell<TableListObject, String>() {
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setStyle("");
} else {
if (item.equals("Something")) {
setStyle("-fx-background-color: blue");
} else {
setStyle("");
}
}
}
};
});
EDIT 1:
If you want to use the value of another cell in the same row. You will have to use the index of the row and get the items need for the check.
tc.setCellFactory(column - > {
return new TableCell < TableListObject, String > () {
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setStyle("");
} else {
int rowIndex = getTableRow().getIndex();
String valueInSecondaryCell = getTableView().getItems().get(rowIndex).getMethod();
if (valueInSecondaryCell.equals("Something Else")) {
setStyle("-fx-background-color: yellow"); //Set the style in the first cell based on the value of the second cell
} else {
setStyle("");
}
}
}
};
});
EDIT 2:
Improved answer based on suggestion. This uses the referenced object.
else {
TableListObject listObject = (TableListObject) getTableRow().getItem();
if (listObject.getMethod().equals("Something Else")) {
setStyle("-fx-background-color: yellow"); //Set the style in the first cell based on the value of the second cell
} else {
setStyle("");
}
}
In my ListView myList, I want each item(String) to have a mini photo next to it.
Here is my how my ListView myList is defined:
ListView<String> myList = new ListView<String>();
SearchResultList.setCellFactory(new Callback<ListView<String>,ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> list) {
return new ColorRectCell();
}
}
);
I read you must specify a cell factory which updates each item in list. However I don't know how this all works, This is the code where I specify my cell factory
static class ColorRectCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
Image rect = new Image("huisteken.jpg");
ImageView rec = new ImageView(rect);
if (item != null) {
System.out.println("testing" + item +"######");
setGraphic(rec);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
}
Please, any ideas or tips are welcome.
My solution to accomplish this is to set the Cells text to null and to make Graphic contain a Hbox containing both picture and text. So make your updateItem look like this:
#Override
void updateItem(final String item, final boolean empty) {
super.updateItem(item, empty);
// if null, display nothing
if (empty || item == null) {
setText(null);
setGraphic(null);
return;
}
setText(null);
Label textLabel = new Label(item + " ");
final HBox hbox = new HBox();
hbox.setSpacing(5);
Label iconLabel = new Label();
iconLabel.setGraphic(new ImageView(new Image("huisteken.jpg")));
hbox.getChildren().addAll(iconLabel, textLabel);
setGraphic(hbox);
}
`
I am sucessfull in making a table column editable and updating value to it when the cell is double clicked. Now what I want to do is get the value from a txt field and set the value to a particular cell (column) of the selected row. I have gone through many research but could not find a proper answer. Javafx doesn't allow to directly edit values to a table except directly editing the cell and setting its value.
Thank you
This is a sample of so far what I have done.
Setting cellValueFactory to teh table columns
tblColQuantity.setCellValueFactory(cellData -> cellData.getValue()
.quantityProperty());
tblColQuantity.setCellFactory(col -> new IntegerEditingCell());
tblColRateWithoutvat.setCellValueFactory(cellData -> cellData
.getValue().rateWithoutvatProperty());
tblColRateWithoutvat.setCellFactory(col -> new IntegerEditingCell());
tblColTotalWithvat.setCellValueFactory(cellData -> cellData.getValue().totalWithvatProperty());
tblColTotalWithvat.setCellFactory(col -> new IntegerEditingCell());
The Inner class which helps me update the cell data
public class IntegerEditingCell extends TableCell<AddBillTable, Number> {
private final TextField textField = new TextField();
private final Pattern intPattern = Pattern.compile("\\d*\\.\\d+");
// -?\\d+
public IntegerEditingCell() {
textField.focusedProperty().addListener(
(obs, wasFocused, isNowFocused) -> {
if (!isNowFocused) {
processEdit();
}
});
textField.setOnAction(event -> processEdit());
}
private void processEdit() {
String text = textField.getText();
if (intPattern.matcher(text).matches()) {
commitEdit(Float.parseFloat(text));
} else {
cancelEdit();
}
}
#Override
public void updateItem(Number value, boolean empty) {
super.updateItem(value, empty);
if (empty || value.equals(null)) {
setText(null);
setGraphic(null);
} else if (isEditing()) {
setText(null);
textField.setText(value.toString());
setGraphic(textField);
}/*
* else if (!empty){ textField.setText(value.toString()); }
*/else {
// if((!value.toString().equals(null)) || (value==null)){
setText(value.toString());
setGraphic(null);
System.out.println("Updated");
System.out.println(this.textField.getText());
// }
}
}
#Override
public void startEdit() {
super.startEdit();
Number value = getItem();
if (value != null) {
textField.setText(value.toString());
setGraphic(textField);
setText(null);
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setGraphic(null);
}
// This seems necessary to persist the edit on loss of focus; not sure
// why:
#Override
public void commitEdit(Number value) {
super.commitEdit(value);
// ((PurchaseDetail)this.getTableRow().getItem()).setQuantity(value.floatValue());
System.out.println("Commit edit " + value);
detectEditedCell(value);
}
}
You can just get the selected item from the table, and call the appropriate set method corresponding to the property that the column represents.
For example, if you wanted a text field to update the quantity of the currently selected row, you would do:
TextField textField = new TextField();
textField.setOnAction(e -> {
AddBillTable selectedItem = table.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
selectedItem.setQuantity(Integer.parseInt(textField.getText()));
}
});
As long as you are implementing your model class (AddBillTable in your example) with JavaFX observable properties (StringProperty, IntegerProperty, etc), then changing the property value will automatically update the table.
Actually I have a problem in my JavaFX app using TableView. I don't no why but, when I load data to TableView during runtime, the JavaFX is not rendering some rows, as you can see in the picture bellow:
But, when I resize the column, the data is displayed:
Bellow follow the source code used:
public void loadData()
{
// Define the TableView columns using Reflection defined by ResultSetMetadata
ArrayList<TableColumn> gridColumns = defineGridColumns(data.get(0));
this.tableView.getColumns().clear();
this.tableView.getColumns().addAll(gridColumns);
// Load data to TableView
this.tableView.setItems(FXCollections.observableArrayList(data));
}
private void defineGridColumns(Object singleData)
{
ArrayList<TableColumn> gridColumns = new ArrayList<>();
Field[] fields = singleData.getClass().getFields();
for (int i = 0; i < fields.length; i++)
{
TableColumn column = createTableColumn(fields[i].getName());
this.gridColumns.add(column);
}
return gridColumns;
}
private TableColumn createTableColumn(String columnName)
{
TableColumn column = new TableColumn(columnName);
column.setCellValueFactory(new PropertyValueFactory(columnName));
column.setPrefWidth(columnName.length() * 20);
HBox box = new HBox();
box.setAlignment(Pos.CENTER);
box.prefWidthProperty().bind(column.widthProperty().subtract(5));
box.setSpacing(10.0);
box.getChildren().addAll(new Label(column.getText()));
column.setGraphic(box);
// Align the cell content in center
column.setCellFactory(new Callback<TableColumn, TableCell>()
{
#Override
public TableCell call(TableColumn param)
{
TableCell cell = new TableCell()
{
#Override
public void updateItem(Object item, boolean empty)
{
if (item != null)
{
setText(item.toString());
}
}
};
cell.setAlignment(Pos.CENTER);
return cell;
}
});
return column;
}
Well, what I'm doing wrong? I already update my Java to the lastest version (JDK 1.8.11).
Thanks to everybody!
Palliative Solution
As resizing column width triggers JavaFX to display the data, I did a method that changes all columns sizes after the data is loaded:
public void loadData()
{
// Define the TableView columns using Reflection defined by ResultSetMetadata
ArrayList<TableColumn> gridColumns = defineGridColumns(data.get(0));
this.tableView.getColumns().clear();
this.tableView.getColumns().addAll(gridColumns);
// Load data to TableView
this.tableView.setItems(FXCollections.observableArrayList(data));
// HACK to force JavaFX display all data
final TrendAnalysisTabController thisController = this;
Platform.runLater(new Runnable()
{
#Override
public void run()
{
thisController.adjustAllColumnWidths();
}
});
}
private void adjustAllColumnWidths()
{
TableViewSkin<?> skin = (TableViewSkin<?>) this.tableView.getSkin();
TableHeaderRow headerRow = skin.getTableHeaderRow();
NestedTableColumnHeader rootHeader = headerRow.getRootHeader();
for (TableColumnHeader columnHeader : rootHeader.getColumnHeaders())
{
try
{
TableColumn<?, ?> column = (TableColumn<?, ?>) columnHeader.getTableColumn();
if (column != null)
{
// Changes the width column and rollback it
double prefWidth = column.getPrefWidth();
column.setPrefWidth(prefWidth + 0.01);
column.setPrefWidth(prefWidth);
}
}
catch (Throwable e)
{
log.log(Level.SEVERE, "Error adjusting columns widths: " + e.getMessage(), e);
}
}
}
because TableCells are reused, you need to explicitly "clear" them in your updateItem method:
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else{
setText(item.toString());
}
}
I'm not sure if this fixes your problem, but when creating a TableCell implementation, your updateItem(...) method must call super.updateItem(...):
column.setCellFactory(new Callback<TableColumn, TableCell>()
{
#Override
public TableCell call(TableColumn param)
{
TableCell cell = new TableCell()
{
#Override
public void updateItem(Object item, boolean empty)
{
// Don't omit this:
super.updateItem(item, empty);
if (item != null)
{
setText(item.toString());
}
}
};
cell.setAlignment(Pos.CENTER);
return cell;
}
});