This question already has answers here:
DatePicker in javafx TableCell
(4 answers)
Closed 5 years ago.
How can I add to the column of a javafx table view a datepicker for an inline edit?
<TableView fx:id="timelineTable" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="dateColumn" prefWidth="85.0" text="%timeline.date" />
</columns>
</TableView>
You need to implement your custom TableCell where you need to #Override the updateItem method. This method should set the graphic to be a DatePicker.
Alternatively, you will implement an editable TableCell where you only set the
DatePicker as graphic when the cell is actually being edited.
Here is a piece of code that might be helpful to implement your idea:
Something more complete is here.
Callback<TableColumn<String, String>, TableCell<String, String>> cellFactory = new Callback<TableColumn<String, String>, TableCell<String, String>>() {
#Override
public TableCell call(final TableColumn<String, String> param) {
final TableCell<String, String> cell = new TableCell<String, String>() {
final DatePicker datePicker = new DatePicker();
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
setGraphic(datePicker);
setText(null);
}
}
};
return cell;
}
};
Related
so I have the following problem.
I have a JavaFX TableView, where all the Cells has the same styling but one. For that one cell I would like to remove all the styling, but I guess the RowFactory has some priority or whatever.
I have some kind of code like that:
FXML
<TableView fx:id="tableView">
<columns>
<TableColumn fx:id="tcolNoStyle"/>
<TableColumn fx:id="tcolStyled"/>
</columns>
</TableView>
Controller
public class TableController {
#FXML
TableView<TableData> tableView;
#FXML
TableColumn<TableData, String> tcolNoStyle;
#FXML
TableColumn<TableData, String> tcolStyled;
#FXML
public void initialize(){
tableView.setRowFactory(row -> new RowFactory());
tcolNoStyle.setCellFactory(cell -> new CellFactoryForNoStyling());
}
}
The Data behind the table
public class TableData {
public final SimpleStringProperty noStyleTextProperty;
public final SimpleStringProperty styledTextProperty;
public TableData(){
noStyleTextProperty = new SimpleStringProperty();
styledTextProperty = new SimpleStringProperty();
}
}
RowFactory
public class RowFactory extends TableRow<TableData> {
public RowFactory(){
itemProperty().addListener(((observable, oldValue, newValue) -> {
if (newValue != null){
setStyle("-fx-text-alignment: right");
}
}));
}
}
CellFactory that one no styled Cell
public class CellFactoryForNoStyling extends TableCell<TableData, String> {
public CellFactoryForNoStyling(){
super();
setStyle(null);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setStyle(null);
}
}
So what I want is, that only that one column should have no style
Thank you in advance!
The problem here is the fact that the -fx-text-alignment property is inherited. setStyle(null) only makes sure there are no additional changes done for the node it's called for.
The probably simplest option would be to simply specify the default value using setStyle:
public CellFactoryForNoStyling() {
setStyle("-fx-text-alignment: left");
}
You could leave the styling to a CSS stylesheet though. This is much more convenient than using inline styles, since it's much easier this way to deal with selection, focus, ect.
You could e.g. add the following stylesheet to the scene; this way you do not to use a custom cellValueFactory/rowFactory:
/* default cell style */
.my-table .table-cell {
-fx-text-alignment: right;
}
/* overwrite above style using selector with higher specifity */
.my-table .table-cell.unstyled {
-fx-text-alignment: inherit;
}
<TableView fx:id="tableView" styleClass="my-table"> <!-- style class added here-->
<columns>
<TableColumn fx:id="tcolNoStyle" styleClass="unstyled"/> <!-- style class added here -->
<TableColumn fx:id="tcolStyled"/>
</columns>
</TableView>
Here is code: Contoller class:
#FXML private TableView<User> table;
#FXML private TableColumn<User,String> view;
method() {.....
` view.setCellValueFactory(
new PropertyValueFactory("DUMMY"));
Callback<TableColumn<User, String>, TableCell<User, String>> cellFactory
= new Callback<TableColumn<User, String>, TableCell<User, String>>() {
public TableCell call( TableColumn<User, String> param) {
final TableCell<User, String> cell = new TableCell<User, String>() {
Button btn = new Button("View");
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
User user = getTableView().getItems().get(getIndex());
System.out.println(user.username
+ " " + user.name);
}
});
setGraphic(btn);
setText(null);
}
}
};
return cell;
}
};
view.setCellFactory(cellFactory);
//add observablelist
table.getItems().setAll(datas);
}`
I have borrowed code from here: How to add button in JavaFX table view
Indeed I have nothing do view in my View column.
Compiler complains that I cannot use parameterless new PropertyValueFactory<>("DUMMY")) in jdk 1.7
Moreover why I cannot use such expression for button column #FXML private TableColumn view?
I also should note that I changed original code with lambda (possible just in 1.8).
As the title states, I'm trying to enable/disable a button within a table row based upon a boolean within that table row's data. Here's my code so far:
col.setCellFactory(new Callback<TableColumn<ExampleRow, String>, TableCell<ExampleRow, String>>() {
#Override
public TableCell call(final TableColumn<ExampleRow, String> param){
final Button btn = new Button("Save");
final TableCell<ExampleRow, String> cell = new TableCell<ExampleRow, String>(){
#Override
public void updateItem(String item, boolean empty){
super.updateItem(item, empty);
if(empty){
setGraphic(null);
setText(null);
} else {
btn.setPrefWidth(col.getWidth());
btn.setPadding(Insets.EMPTY);
btn.setOnAction(event -> {
});
setGraphic(btn);
setText(null);
}
}
};
ExampleRow row = (ExampleRow)cell.getTableRow().getItem(); //NPE here
btn.setDisable(!row.hasChanged());
return cell;
}
});
Unfortunately my code breaks on the fifth from the bottom line. If I exclude that line and change the line below to btn.setDisable(true) it works wonderfully. What can I do to disable this button based upon the data in which the button resides?
You aren't using the item anyways, so you could just make it a Boolean and use the value of the changed property. This allows you to enable/disable the button in the updateItem method:
Example:
public static class Item {
private final BooleanProperty changed = new SimpleBooleanProperty();
public final boolean isChanged() {
return this.changed.get();
}
public final void setChanged(boolean value) {
this.changed.set(value);
}
public final BooleanProperty changedProperty() {
return this.changed;
}
}
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView();
table.getItems().addAll(new Item(), new Item(), new Item());
TableColumn<Item, Boolean> column = new TableColumn<>();
column.setCellValueFactory(cd -> cd.getValue().changedProperty());
column.setCellFactory(col -> new TableCell<Item, Boolean>() {
final Button btn = new Button("Save");
{
btn.setOnAction(evt -> {
Item item = (Item) getTableRow().getItem();
item.setChanged(false);
});
}
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
btn.setDisable(!item);
setGraphic(btn);
}
}
});
table.getColumns().add(column);
Button btn = new Button("change");
btn.setOnAction((ActionEvent event) -> {
Item item = table.getSelectionModel().getSelectedItem();
if (item != null) {
item.setChanged(true);
}
});
VBox root = new VBox(btn, table);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
BTW: TableView uses the cellFactory to create the cells. The item, table and tableRow properties are updated later. Therefore retrieving any of those values in the cellFactory's call method itself makes no sense, since none of those values have been assigned at that time.
I have a treetableview with 4 level hierarchy. I want to have a column with cell factory as combobox. but this combobox should be visible only at the last child level and not the parent level. Is that possible to achieve?
Edit: I tried the following as per suggestions received.
ObservableList ADM = WSData.getADMObjectMapList();
tbAdmMap.setCellFactory(new Callback<TreeTableColumn<ProjectPlan, String>, TreeTableCell<ProjectPlan, String>>() {
#Override
public TreeTableCell<ProjectPlan, String> call(TreeTableColumn<ProjectPlan, String> param) {
TreeTableCell<ProjectPlan, String> cell = new TreeTableCell<ProjectPlan, String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
System.out.println(getItem());
if (getString().equals("")) {
setGraphic(null);
} else {
ComboBox<String> comboBox = new ComboBox(ADM);
comboBox.setValue(item);
setGraphic(comboBox);
}
}
private String getString() {
return getItem() == null ? "" : getItem();
}
};
return cell;
}
});
It is giving me the proper look as I want but not taking the cell into edit mode. As in the onCommitEdit method is not getting called.
I'm having some issues with deleting datas from my TableView in JavaFX.
TabeView receives its data from a static ObservableList.
Problem: TableView shows 6 rows at a time. When there are for example 6 data-objects in my ObservableList and i delete 1 of them, the TableView seems to have some update-issues:
Error
As you can see, the red highlighted row seems to be a copy of a still existing value in
my ObservableList. You cannot select this row cause there is of course no existing
value in ObservableList. This behavior keeps appearing after deleting some more values:
enter link description here
All highlights "rows" are not selectable cause there is no corresponding value in my ObservableList. Only after deleting the last value / row in TableView it is refreshed and becomes empty.
My ObservableList ist static
public static ObservableList<ImageData> datas_all;
Deletion is pretty simple
#FXML
private TableView<ImageData> imageTable;
...
#FXML
private void handleDeleteImage()
{
ImageData img_data = imageTable.getSelectionModel().getSelectedItem();
Main.datas_all.remove(img_data);
//if(Main.datas_flickr.contains(img_data))
// Main.datas_flickr.remove(img_data);
//Main.db_adapter.deleteImage(new Integer[]{img_data.getKey()});
//File del_file = new File(img_data.getPath());
//del_file.delete();
}
TableView consists of two rows defined by
#FXML
private TableColumn<ImageData,Image> columnImage;
#FXML
private TableColumn<ImageData,String> columnName;
...
public void redefineTableView()
{
columnImage.setCellFactory(new Callback<TableColumn<ImageData, Image>, TableCell<ImageData, Image>>()
{
#Override
public TableCell<ImageData, Image> call(TableColumn<ImageData, Image> param)
{
final ImageView imgView = new ImageView();
imgView.setFitHeight(100);
imgView.setFitWidth(100);
TableCell<ImageData, Image> cell = new TableCell<ImageData, Image>()
{
public void updateItem(Image image, boolean empty)
{
if(image != null)
imgView.setImage(image);
}
};
cell.setGraphic(imgView);
return cell;
}
});
columnName.setCellFactory(new Callback<TableColumn<ImageData, String>, TableCell<ImageData, String>>()
{
#Override
public TableCell<ImageData, String> call(TableColumn<ImageData, String> param)
{
TableCell<ImageData, String> cell = new TableCell<ImageData, String>()
{
private Text text;
public void updateItem(String string, boolean empty)
{
super.updateItem(string, empty);
if (!isEmpty())
{
text = new Text(string);
text.setWrappingWidth(170);
setGraphic(text);
}
}
};
return cell;
}
});
columnName.setCellValueFactory(new PropertyValueFactory<ImageData, String>("name"));
columnImage.setCellValueFactory(new PropertyValueFactory<ImageData, Image>("image"));
imageTable.setItems(Main.datas_all);
}
I've googled this problem but nobody else seems to have it.
Please help me! =)
This has been asked before, but I can't find it now. The issue is that your updateItem(...) method does not properly handle the case where the image is null (or the cell is empty). This will be exactly the case when you delete an item from the table. You need:
TableCell<ImageData, Image> cell = new TableCell<ImageData, Image>()
{
public void updateItem(Image image, boolean empty)
{
if(image == null) {
setGraphic(null);
} else {
imgView.setImage(image);
setGraphic(imgView);
}
}
};
return cell;
and similarly for the other cell factory.