So, I am trying to add a button to a column using Table View in JavaFX. I have successfully created a single button for one column; using the same code to add another button on another column with a small change of variables is resulting me in one error which I am unable to fix. The error is that it is not allowing me to use the word super. Below is the code in which I am having the error on;
TableColumn<UserDetails, UserDetails> addColumn = column("Add", ReadOnlyObjectWrapper<UserDetails>::new, 50);
addColumn.setCellFactory(col -> {
Button addButton = new Button("Add");
TableCell<UserDetails, UserDetails> addCell = new TableCell<UserDetails, UserDetails>() {
public void addItems(UserDetails userDetails, boolean empty) {
super.addItems(userDetails, empty); //This line is the error (super)
if (empty) {
setGraphic(null);
} else {
setGraphic(addButton);
}
}
};
addButton.setOnAction(event -> add(addCell.getItem(), primaryStage));
return addCell;
});
what am I doing wrong?
As you can see in the TableCell javadoc there is no addItems method in TableCell. You probably wanted to use the updateItem method:
#Override
protected void updateItem(UserDetails userDetails, boolean empty) {
super.updateItem(userDetails, empty);
...
Related
I have tried to research about this, but could not find any examples. The examples I found were regarding normal TableView only. I could only create a JFXTreeTableView with an object and list out String. Any help would be appreciated! Thanks!
I need to put a button or basically any other object than a string into a TreeTableView.
Updated to make it clear on what I wanted it to look like, and the solution is below.
With reference to this post, I was trying to add a Button(Specifically JFXButton) into a TreeTableView(Specifically JFXTreeTableView)
How to add button in JavaFX table view
However, the post only talks about TableView. After analyzing the codes I tried to modify the codes to work with TreeTableView and TreeTableCell instead.
Using the sample codes from JFoenix and modifying it as seen in the codes snippets below, I could load a JFXButton into a JFXTreeTableView. (Also works with normal Button. Just replace the JFXButton to Button)
JFXTreeTableColumn<User, String> settingsColumn = new JFXTreeTableColumn<>("Others");
settingsColumn.setPrefWidth(100);
Callback<TreeTableColumn<User, String>, TreeTableCell<User, String>> cellFactory
= //
new Callback<TreeTableColumn<User, String>, TreeTableCell<User, String>>() {
#Override
public TreeTableCell call(final TreeTableColumn<User, String> param) {
final TreeTableCell<User, String> cell = new TreeTableCell<User, String>() {
final JFXButton btn = new JFXButton("Just Do it");
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
btn.setButtonType(JFXButton.ButtonType.RAISED);
btn.setOnAction(event -> {
//Button Action here
});
setGraphic(btn);
setText(null);
}
}
};
return cell;
}
};
settingsColumn.setCellFactory(cellFactory);
//Also remember to add the new column in
treeView.getColumns().setAll(deptColumn, ageColumn, empColumn, settingsColumn);
This is the end result:
I have to display 5000 nodes using ListView. Every node contains complex controls but only some text part is different in nodes. How can i reuse existing nodes controls to recreate my cells while scrolling
The answer of James_D points into the right direction. Normally, in JavaFX you shouldn't worry about reusing existing nodes - the JavaFX framework does exactly this, out-of-the-box. If you want to implement some custom cell rendering, you need to set a cell factory, and that usually looks like this:
listView.setCellFactory(new Callback() {
#Override
public Object call(Object param) {
return new ListCell<String>() {
// you may declare fields for some more nodes here
// and initialize them in an anonymous constructor
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty); // Default behaviour: zebra pattern etc.
if (empty || item == null) { // Default technique: take care of empty rows!!!
this.setText(null);
} else {
this.setText("this is the content: " + item);
// ... do your custom rendering!
}
}
};
}
});
Please note: this should work, but is merely illustrative - we Java Devs know that e.g., we would use a StringBuilder for String concatenation, especially in such cases where the code will execute very often.
If you want some complex rendering, you may build that graphic with additional nodes and set them as graphics property with setGraphic(). This works similar to the Label control:
// another illustrative cell renderer:
listView.setCellFactory(new Callback() {
#Override
public Object call(Object param) {
return new ListCell<Integer>() {
Label l = new Label("X");
#Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
this.setGraphic(null);
} else {
this.setGraphic(l);
l.setBackground(
new Background(
new BackgroundFill(
Color.rgb(3 * item, 2 * item, item),
CornerRadii.EMPTY,
Insets.EMPTY)));
l.setPrefHeight(item);
l.setMinHeight(item);
}
}
};
}
});
I am creating a program in JavaFX which lists tasks from a data base and displays a button for each row with allows a user to register the task as claimed in the database. I used the code on this link to help me with the buttons for each row: https://gist.github.com/jewelsea/3081826.
However, after changing the code to fit my program, i am getting an error in relation to setting the action of the cellButton variable. I have also added the class that calls this method, just in case.
CANNOT FIND SYMBOL CONSTRUCTOR, EVENTHANDLER DOES NOT TAKE PARAMETERS..
& METHOD DOES NOT OVERRIDE OR IMPLEMENT A METHOD FROM A SUPERTYPE (I am guessing this error is as a result of the first two errors).
//Define the button cell
private class ButtonCell extends TableCell<task, Boolean> {
final Button cellButton = new Button("Claim");
ButtonCell(){
//Action when the button is pressed
cellButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
// get Selected Item
task currentPerson = (task) ButtonCell.this.getTableView().getItems().get(ButtonCell.this.getIndex());
//remove selected item from the table list
newMan.claimTask(currentPerson.getTaskID());
}
});
}
//Display button if the row is not empty
#Override
protected void updateItem(Boolean t, boolean empty) {
super.updateItem(t, empty);
if(!empty){
setGraphic(cellButton);
}
}
}
x
private TableView createTasksTable() {
TableView tableView = new TableView();
TableColumn<task,String> firstNameCol = new TableColumn<>("Task");
firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<task, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<task, String> p) {
// p.getValue() returns the Person instance for a particular TableView row
return new SimpleStringProperty(p.getValue().getName());
}
});
//Insert Button
TableColumn col_action = new TableColumn<>("Action");
tableView.getColumns().add(col_action);
col_action.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<task, Boolean>,
ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<task, Boolean> p) {
return new SimpleBooleanProperty(p.getValue() != null);
}
});
//Adding the Button to the cell
col_action.setCellFactory(
new Callback<TableColumn<task, Boolean>, TableCell<task, Boolean>>() {
#Override
public TableCell<task, Boolean> call(TableColumn<task, Boolean> p) {
return new ButtonCell();
} });
tableView.getColumns().addAll(firstNameCol);
return tableView;
}
You have probably imported the wrong EventHandler. Make sure you have
import javafx.event.EventHandler ;
and not something from awt.
I have the following problem creating custom cell factory of a ComboBox from an FXML file created with Scene Builder in JavaFX:
I created a custom cell factory of Labels. It works fine when the user clicks on the items. The y are displayed in the "button" area. But when the user wants to click on another items the previously clicked item is gone.
Here is the code of the combobox cell factory:
idCardOnlineStatusComboBox.setCellFactory(new Callback<ListView<Label>, ListCell<Label>>() {
#Override public ListCell<Label> call(ListView<Label> param) {
final ListCell<Label> cell = new ListCell<Label>() {
#Override public void updateItem(Label item,
boolean empty) {
super.updateItem(item, empty);
if(item != null || !empty) {
setGraphic(item);
}
}
};
return cell;
}
});
I suppose there is a problem in the cell factory but i can't figure out where it is.
I extract the combobox from the fxml with this code:
#FXML private ComboBox idCardOnlineStatusComboBox;
then i fill the combobox with this:
idCardOnlineStatusComboBox.getItems().addAll(
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Online.Title"), new ImageView(onlineImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Away.Title"), new ImageView(awayImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.DoNotDisturb.Title"), new ImageView(doNotDisturbImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Invisible.Title"), new ImageView(offlineImg)),
new Label(Resource.getStringFor("MainForm.Pane.MenuBar.Vortex.OnlineStatus.Offline.Title"), new ImageView(offlineImg))
);
The disappearing behavior may be a bug. You can file it to JavaFX Jira, and let the Oracle guys decide it further. Additionally you can investigate the ComboBox.setCellFactory(...) source code for the reason of this behavior and find workaround. But my suggestion is to use the ComboBox Cell's (ListCell) internal Labelled component, instead of yours:
#Override
public void updateItem(Label item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item.getText());
setGraphic(item.getGraphic());
} else {
setText(null);
setGraphic(null);
}
}
Note the else part of the code, cover all use cases when writing an if-statement.
How can I make an auto wrap ListView (multiline when the text is too long) in JavaFX 2? I know that if I put a \n to the string, it will be multiline, but the content is too dynamic.
Or is there a good way to put \n to the String after every xyz pixel length?
You can put a TextArea in the ListCell.graphicProperty(). This is usually used to set an icon in a list cell but can just as easy to set to any Node subclass.
Here is the exact code how I did it finally.
ListView<String> messages = new ListView<>();
messages.relocate(10, 210);
messages.setPrefSize(this.getPrefWidth() - 20, this.getPrefHeight() - 250);
messages.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> list) {
final ListCell cell = new ListCell() {
private Text text;
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty()) {
text = new Text(item.toString());
text.setWrappingWidth(messages.getPrefWidth());
setGraphic(text);
}
}
};
return cell;
}
});
There is no need to create additional controls such as TextArea or Text. It is enough to just setWrapText(true) of the ListCell and setPrefWidth(50.0) or so. It will be automatically rewrapped on resize.
Here is my working code in Kotlin:
datasets.setCellFactory()
{
object : ListCell<Dataset>()
{
init
{
isWrapText = true
prefWidth = 50.0
}
override fun updateItem(item: Dataset?, empty: Boolean)
{
super.updateItem(item, empty)
text = item?.toString()
}
}
}
By the way, this is how I made it to correctly wrap CamelCase words:
replace(Regex("(?<=\\p{javaLowerCase})(?=\\p{javaUpperCase})|(?<=[_.])"), "\u2028")
Here \u2028 is the Unicode soft line break character, which javaFX respects.