I followed the tutorial about TableView in Oracle docs, and I want to do the same thing, but instead of showing a TextField to modified items, I want to show a RadioButton.
(I created the TableView with RadionButton on it)
I used the tutorial at https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm (see Editing Data in the Table) and extended it. As a basis for the values, which should be set by radio buttons I assume an Enumeration.
In my example I extended the Person class with the enum Participation (indicating whether or not the people of the list attending an fictive event) ...
public static enum Participation {
YES,
NO,
MAYBE;
public String toString() {
return super.toString().toLowerCase();
};
}
...
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private final SimpleObjectProperty<Participation> participation;
...
I implemented a RadioButtonCell, which takes an arbitraty EnumSet<T>. So you can use it for every Enumeration and every TableColumn, which should contain RadioButtons.
public static class RadioButtonCell<S,T extends Enum<T>> extends TableCell<S,T>{
private EnumSet<T> enumeration;
public RadioButtonCell(EnumSet<T> enumeration) {
this.enumeration = enumeration;
}
#Override
protected void updateItem(T item, boolean empty)
{
super.updateItem(item, empty);
if (!empty)
{
// gui setup
HBox hb = new HBox(7);
hb.setAlignment(Pos.CENTER);
final ToggleGroup group = new ToggleGroup();
// create a radio button for each 'element' of the enumeration
for (Enum<T> enumElement : enumeration) {
RadioButton radioButton = new RadioButton(enumElement.toString());
radioButton.setUserData(enumElement);
radioButton.setToggleGroup(group);
hb.getChildren().add(radioButton);
if (enumElement.equals(item)) {
radioButton.setSelected(true);
}
}
// issue events on change of the selected radio button
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
#SuppressWarnings("unchecked")
#Override
public void changed(ObservableValue<? extends Toggle> observable,
Toggle oldValue, Toggle newValue) {
getTableView().edit(getIndex(), getTableColumn());
RadioButtonCell.this.commitEdit((T) newValue.getUserData());
}
});
setGraphic(hb);
}
}
}
You now have to adjust the CellFactory of the particular TableColumn
participationColumn.setCellFactory((param) -> new RadioButtonCell<Person, Participation>(EnumSet.allOf(Participation.class)));
Finally update the actual value of your data on a commit as usual:
participationColumn.setCellValueFactory(new PropertyValueFactory<Person, Participation>("participation"));
participationColumn.setOnEditCommit(
new EventHandler<CellEditEvent<Person, Participation>>() {
#Override
public void handle(CellEditEvent<Person, Participation> t) {
((Person) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setParticipation(t.getNewValue());
}
}
);
gkri, thank you for the nice code! This is very useful. I have one additional remark: Of course the new SimpleObjectProperty needs its get & set methods. Without the getter the table will not properly update, especially when sorting or, with TreeTableView, when expanding or collapsing nodes:
public void setParticipation(Participation p){
participation.set(p);
}
public Participation getParticipation(){
return participation.get();
}
So the full code sample:
import java.util.EnumSet;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TableViewSample extends Application {
private final TableView<Person> table = new TableView<>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com",Participation.MAYBE),
new Person("Isabella", "Johnson", "isabella.johnson#example.com",Participation.MAYBE),
new Person("Ethan", "Williams", "ethan.williams#example.com",Participation.MAYBE),
new Person("Emma", "Jones", "emma.jones#example.com",Participation.MAYBE),
new Person("Michael", "Brown", "michael.brown#example.com",Participation.MAYBE));
final HBox hb = new HBox();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(650);
stage.setHeight(550);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
table.setMinWidth(640);
TableColumn<Person,String> firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<>("firstName"));
TableColumn<Person,String>lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<>("lastName"));
TableColumn<Person,String> emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<>("email"));
TableColumn<Person,Participation> participationColumn = new TableColumn("Participation");
participationColumn.setCellFactory((param) -> new RadioButtonCell<Person, Participation>(EnumSet.allOf(Participation.class)));
participationColumn.setCellValueFactory(new PropertyValueFactory<Person, Participation>("participation"));
participationColumn.setOnEditCommit(
new EventHandler<CellEditEvent<Person, Participation>>() {
#Override
public void handle(CellEditEvent<Person, Participation> t) {
((Person) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setParticipation(t.getNewValue());
}
}
);
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, participationColumn );
final TextField addFirstName = new TextField();
addFirstName.setPromptText("First Name");
addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
final TextField addLastName = new TextField();
addLastName.setMaxWidth(lastNameCol.getPrefWidth());
addLastName.setPromptText("Last Name");
final TextField addEmail = new TextField();
addEmail.setMaxWidth(emailCol.getPrefWidth());
addEmail.setPromptText("Email");
final Button addButton = new Button("Add");
addButton.setOnAction((ActionEvent e) -> {
data.add(new Person(
addFirstName.getText(),
addLastName.getText(),
addEmail.getText(),
Participation.NO
));
addFirstName.clear();
addLastName.clear();
addEmail.clear();
});
hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);
hb.setSpacing(3);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table, hb);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static enum Participation {
YES,
NO,
MAYBE;
public String toString() {
return super.toString().toLowerCase();
};
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private final SimpleObjectProperty<Participation> participation = new SimpleObjectProperty<Participation>();
private Person(String fName, String lName, String email, Participation p ) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
this.participation.setValue(p);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
public void setParticipation(Participation p){
participation.set(p);
}
public Participation getParticipation(){
return participation.get();
}
}
public static class RadioButtonCell<S,T extends Enum<T>> extends TableCell<S,T>{
private EnumSet<T> enumeration;
public RadioButtonCell(EnumSet<T> enumeration) {
this.enumeration = enumeration;
}
#Override
protected void updateItem(T item, boolean empty)
{
super.updateItem(item, empty);
if (!empty)
{
// gui setup
HBox hb = new HBox(7);
hb.setAlignment(Pos.CENTER);
final ToggleGroup group = new ToggleGroup();
// create a radio button for each 'element' of the enumeration
for (Enum<T> enumElement : enumeration) {
RadioButton radioButton = new RadioButton(enumElement.toString());
radioButton.setUserData(enumElement);
radioButton.setToggleGroup(group);
hb.getChildren().add(radioButton);
if (enumElement.equals(item)) {
radioButton.setSelected(true);
}
}
// issue events on change of the selected radio button
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
#SuppressWarnings("unchecked")
#Override
public void changed(ObservableValue<? extends Toggle> observable,
Toggle oldValue, Toggle newValue) {
getTableView().edit(getIndex(), getTableColumn());
RadioButtonCell.this.commitEdit((T) newValue.getUserData());
}
});
setGraphic(hb);
}
}
}
}
Simly do it like in the example 12-8 Editing a Table Cell.
Define a EditingCell like there(at the bottom) but simply replace the TextField with a RadioButton.
If you need further assistance, write a comment under this answer.
Happy Coding,
Kalasch
Related
I need to make a project using javafx where there is a table (for example of users), with another table inside each row (for example orders of the user).
I would like it to be toggle-able so I would extend a row by clicking on it and then the inner table/s would be visable.
Some draw for the gui exmaple:
This will be useful i guess
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TreeTableView extends Application {
private TableView<Person> table = new TableView<Person>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(450);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
constructTable();
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
private void constructTable() {
TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
TableColumn<Person, String> emailCol = new TableColumn<Person, String>("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
table.setItems(getData());
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
table.setRowFactory(tv -> new TableRow<Person>() {
Node detailsPane ;
{
this.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected ) {
detailsPane = constructSubTable(getItem());
this.getChildren().add(detailsPane);
} else {
this.getChildren().remove(detailsPane);
}
this.requestLayout();
});
}
#Override
protected double computePrefHeight(double width) {
if (isSelected()) {
return super.computePrefHeight(width)+detailsPane.prefHeight(60);
} else {
return super.computePrefHeight(width);
}
}
#Override
protected void layoutChildren() {
super.layoutChildren();
if (isSelected()) {
double width = getWidth();
double paneHeight = detailsPane.prefHeight(width);
detailsPane.resizeRelocate(0, getHeight()-paneHeight, width, paneHeight);
}
}
});
}
private TableView<Address> constructSubTable(Person person) {
List<Address> addresses = new ArrayList<>(); addresses.add(person.getAddress());
TableView<Address> subTable = new TableView<Address>();
TableColumn<Address, String> streetCol = new TableColumn<Address, String>("Street");
streetCol.setMinWidth(100);
streetCol.setCellValueFactory(new PropertyValueFactory<Address, String>("Street"));
TableColumn<Address, String> cityCol = new TableColumn<Address, String>("City");
cityCol.setMinWidth(100);
cityCol.setCellValueFactory(new PropertyValueFactory<Address, String>("city"));
subTable.setItems(FXCollections.observableArrayList(addresses));
subTable.getColumns().addAll(streetCol, cityCol);
subTable.setPrefHeight(50+(addresses.size()*30));
subTable.setStyle("-fx-border-color: #42bff4;");
return subTable;
}
private ObservableList<Person> getData() {
return FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith#example.com","Jacob Street","NY"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com","Isabella Street","DL"),
new Person("Ethan", "Williams", "ethan.williams#example.com","Ethan Street"," ML"),
new Person("Emma", "Jones", "emma.jones#example.com","Emma Street","EL"),
new Person("Michael", "Brown", "michael.brown#example.com","Michael Street","ML"));
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Address address;
Person(String fName, String lName, String email,String streetS, String cityS) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
address = new Address(streetS, cityS);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
public static class Address{
private final SimpleStringProperty street;
private final SimpleStringProperty city;
Address(String streetS, String cityS) {
this.street = new SimpleStringProperty(streetS);
this.city = new SimpleStringProperty(cityS);
}
public String getStreet() {
return street.get();
}
public void setStreet(String streetS) {
street.set(streetS);
}
public String getCity() {
return city.get();
}
public void setCity(String cityS) {
city.set(cityS);
}
}
}
https://gist.github.com/sh9va/c81b9de44811cc860951701124941c1e
You need to use TreeTableView in Scene Build and so adding the columns you want, aside from that, you should create the TabPane layout which will contain the information you want.
p.s do not forget to make a Model, TreeTableView needs a model to create the cells.
As a part of my project i want display a tableview which should be disabled for some time(on editting time nb:not table editting).So that i got a working code which will disable the tableview.This is the working code,
table.setSelectionModel(null);
So my problem is after editing process is over when click a button i want to enable it back,but unfortunately i could'nt find any alternative code for that.Any one please suggest me the code which will enable the row selection.Any answer will appreciable.
You can retrieve the default selection model when you create the table:
TableView<T> table = new TableView<>();
TableViewSelectionModel<T> defaultSelectionModel = table.getSelectionModel();
where T is the type for your table. (Of course, if you are using FXML, just put the second line in the controller's initialize() method.)
Then to disable row selection do
table.setSelectionModel(null);
and to enable it again
table.setSelectionModel(defaultSelectionModel);
Here is a SSCCE:
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TableView.TableViewSelectionModel;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TableWithDisabledSelection extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Person> table = new TableView<>();
TableViewSelectionModel<Person> defaultSelectionModel = table.getSelectionModel();
table.getColumns().add(column("First Name", Person::firstNameProperty));
table.getColumns().add(column("Last Name", Person::lastNameProperty));
table.getColumns().add(column("Email", Person::emailProperty));
table.getItems().addAll(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
CheckBox enableSelection = new CheckBox("Enable selection");
enableSelection.setSelected(true);
enableSelection.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
table.setSelectionModel(defaultSelectionModel);
} else {
table.setSelectionModel(null);
}
});
BorderPane root = new BorderPane(table);
BorderPane.setAlignment(enableSelection, Pos.CENTER);
BorderPane.setMargin(enableSelection, new Insets(5));
root.setBottom(enableSelection);
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.show();
}
private <S,T> TableColumn<S,T> column(String title, Function<S,Property<T>> prop) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
return col ;
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
private final StringProperty email = new SimpleStringProperty();
public Person(String firstName, String lastName, String email) {
setFirstName(firstName);
setLastName(lastName);
setEmail(email);
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final String lastName) {
this.lastNameProperty().set(lastName);
}
public final StringProperty emailProperty() {
return this.email;
}
public final String getEmail() {
return this.emailProperty().get();
}
public final void setEmail(final String email) {
this.emailProperty().set(email);
}
}
}
I handled this situation with rowfactory like this;
tableView.setRowFactory(param -> new TableRow<Model>()
{
#Override
protected void updateItem(Model item, boolean empty)
{
super.updateItem(item, empty);
if (!empty)
{
disableProperty().bind(item.getFocusable().not());
}
}
});
so, you can bind the disableproperty with suitable property of your tableview model.
I solved the basic problem I was looking at by setting a comparator on the entire table, but what I was initially trying to do was find a way to "click" the header to generate the sorting event.
I'd still like to know how to do this, as I currently do not know of a method to proc sorting methods of the columns, only the table itself.
Call getSortOrder() on the TableView: that returns a list of TableColumns representing the order by which rows are sorted:
An empty sortOrder list means that no sorting is being applied on the
TableView. If the sortOrder list has one TableColumn within it, the
TableView will be sorted using the sortType and comparator properties
of this TableColumn (assuming TableColumn.sortable is true). If the
sortOrder list contains multiple TableColumn instances, then the
TableView is firstly sorted based on the properties of the first
TableColumn. If two elements are considered equal, then the second
TableColumn in the list is used to determine ordering. This repeats
until the results from all TableColumn comparators are considered, if
necessary.
Then just add to, remove from, set, clear, etc the list as you need.
SSCCE:
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TableViewProgrammaticSort extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Person> table = new TableView<>();
TableColumn<Person, String> firstNameCol = column("First Name", Person::firstNameProperty);
TableColumn<Person, String> lastNameCol = column("Last Name", Person::lastNameProperty);
TableColumn<Person, String> emailCol = column("Email", Person::emailProperty);
table.getColumns().add(firstNameCol);
table.getColumns().add(lastNameCol);
table.getColumns().add(emailCol);
table.getItems().addAll(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
ComboBox<TableColumn<Person, ?>> sortCombo = new ComboBox<>();
sortCombo.getItems().add(firstNameCol);
sortCombo.getItems().add(lastNameCol);
sortCombo.getItems().add(emailCol);
sortCombo.setCellFactory(lv -> new ColumnListCell());
sortCombo.valueProperty().addListener((obs, oldColumn, newColumn) -> {
table.getSortOrder().clear();
if (newColumn != null) {
table.getSortOrder().add(newColumn);
}
});
sortCombo.setButtonCell(new ColumnListCell());
BorderPane root = new BorderPane(table, sortCombo, null, null, null);
BorderPane.setMargin(table, new Insets(10));
BorderPane.setMargin(sortCombo, new Insets(10));
BorderPane.setAlignment(sortCombo, Pos.CENTER);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private static class ColumnListCell extends ListCell<TableColumn<Person, ?>> {
#Override
public void updateItem(TableColumn<Person, ?> column, boolean empty) {
super.updateItem(column, empty);
if (empty) {
setText(null);
} else {
setText(column.getText());
}
}
}
private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col ;
}
public static class Person {
private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
private final StringProperty email = new SimpleStringProperty(this, "email");
public Person(String firstName, String lastName, String email) {
this.firstName.set(firstName);
this.lastName.set(lastName);
this.email.set(email);
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final java.lang.String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final java.lang.String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final java.lang.String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final java.lang.String lastName) {
this.lastNameProperty().set(lastName);
}
public final StringProperty emailProperty() {
return this.email;
}
public final java.lang.String getEmail() {
return this.emailProperty().get();
}
public final void setEmail(final java.lang.String email) {
this.emailProperty().set(email);
}
}
public static void main(String[] args) {
launch(args);
}
}
How to
Table column select check box will select
I have select check box in table view and unfortunately,I will select table column at time all check box is un-select,click table column check box only select
how to rearrange in my code help me.
package tableviewwithaddcheckbox;
import com.sun.javafx.runtime.VersionInfo;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
*
* #author reegan
*/
public class TableViewWithAddCheckBox extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage) {
stage.setTitle("People");
// create a table.
final TableView<Person> table = new TableView<>(
FXCollections.observableArrayList(
new Person("Jacob", "Smith"),
new Person("Isabella", "Johnson"),
new Person("Ethan", "Williams"),
new Person("Emma", "Jones"),
new Person("Michael", "Brown")));
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// define the table columns.
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setCellValueFactory(new PropertyValueFactory("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setCellValueFactory(new PropertyValueFactory("lastName"));
TableColumn<Person, Boolean> actionCol = new TableColumn<>("Action");
actionCol.setSortable(false);
// define a simple boolean cell value for the action column so that the column will only be shown for non-empty rows.
actionCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, Boolean>, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Person, Boolean> features) {
return new SimpleBooleanProperty(features.getValue() != null);
}
});
// create a cell value factory with an add button for each row in the table.
actionCol.setCellFactory(new Callback<TableColumn<Person, Boolean>, TableCell<Person, Boolean>>() {
#Override
public TableCell<Person, Boolean> call(TableColumn<Person, Boolean> personBooleanTableColumn) {
return new AddPersonCell(stage, table);
}
});
table.getColumns().setAll(firstNameCol, lastNameCol, actionCol);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getSelectionModel().getSelectedIndices().addListener(new ListChangeListener() {
#Override
public void onChanged(ListChangeListener.Change change) {
System.out.println("-------------------------");
System.out.println(change.getList());
System.out.println("------------------------");
}
});
table.getSelectionModel().getSelectedItems().addListener(new ListChangeListener<Person>() {
#Override
public void onChanged(ListChangeListener.Change<? extends Person> change) {
System.out.println(change.getList());
VersionInfo info = new VersionInfo();
System.out.println(info.getRuntimeVersion());
String version = System.getProperty("java.version");
System.out.println(version);
String vendor = System.getProperty("java.vendor.url");
System.out.println(vendor);
System.out.println(version);
}
});
System.out.println(table.getItems());
stage.setScene(new Scene(table));
stage.show();
}
private class AddPersonCell extends TableCell<Person, Boolean> {
final CheckBox addButton = new CheckBox();
final StackPane paddedButton = new StackPane();
AddPersonCell(final Stage stage, final TableView table) {
paddedButton.setPadding(new Insets(3));
paddedButton.getChildren().add(addButton);
addButton.selectedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t1) {
table.getSelectionModel().select(getTableRow().getIndex());
System.out.println(getTableColumn());
} else {
table.getSelectionModel().clearSelection(getTableRow().getIndex());
}
}
});
}
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(paddedButton);
}
}
}
}
PersonClaa.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package tableviewwithaddcheckbox;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* #author reegan
*/
public class Person {
private StringProperty firstName;
private StringProperty lastName;
public Person(String firstName, String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
public final void setFirstName(String value) { firstNameProperty().set(value); }
public final void setLastName(String value) { lastNameProperty().set(value); }
public String getFirstName() { return firstNameProperty().get(); }
public String getLastName() { return lastNameProperty().get(); }
public StringProperty firstNameProperty() {
if (firstName == null) firstName = new SimpleStringProperty(this, "firstName");
return firstName;
}
public StringProperty lastNameProperty() {
if (lastName == null) lastName = new SimpleStringProperty(this, "lastName");
return lastName;
}
}
My question is how to make a new Table in JavaFX with in the first column the index of the tableRow.
So i've created a class: NrCellFactory.
public class NrCellFactory<S, String> extends TableCellFactory<S,String> {
private class NrCell<S,String> extends TableCell<S,String>{
public NrCell(){
setText(this.getTableRow().getIndex()+"");
}
}
#Override
protected TableCell<S, String> createTableCell(TableColumn<S, String> column) {
return new NrCell();
}
}
and then i set my column where the numbers should be displayed:
nrCol.setCellFactory(new NrCellFactory<Person,String>());
when I load the project, the nrCol has no data...
Can anyone solve the problem?
Thanks
Sample Solution
Here's a solution using a cell factory:
TableColumn numberCol = new TableColumn("#");
numberCol.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() {
#Override public ObservableValue<Person> call(CellDataFeatures<Person, Person> p) {
return new ReadOnlyObjectWrapper(p.getValue());
}
});
numberCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() {
#Override public TableCell<Person, Person> call(TableColumn<Person, Person> param) {
return new TableCell<Person, Person>() {
#Override protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (this.getTableRow() != null && item != null) {
setText(this.getTableRow().getIndex()+"");
} else {
setText("");
}
}
};
}
});
numberCol.setSortable(false);
Simple Alternate Solution
And a simpler sample using a cell value factory and no cell factory for the normal case where all of the items in the backing data list for the table are unique and their index can be looked up via table.getItems().indexOf(p.getValue()):
TableColumn numberCol = new TableColumn("#");
numberCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
#Override public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
return new ReadOnlyObjectWrapper(table.getItems().indexOf(p.getValue()) + "");
}
});
numberCol.setSortable(false);
Why your attempt to do this failed
I couldn't say exactly why your attempt to do this failed as I don't think there is enough code in your question to accurately diagnose the failure. My guess is that you didn't provide a cell value factory for the row and also setting the text in the cell's constructor rather than an updateItem call caused it not to work.
Executable Sample
Here is an executable sample:
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
public class NumberedTableViewSample extends Application {
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(470);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
TableColumn numberCol = new TableColumn("#");
numberCol.setMinWidth(20);
numberCol.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() {
#Override public ObservableValue<Person> call(CellDataFeatures<Person, Person> p) {
return new ReadOnlyObjectWrapper(p.getValue());
}
});
numberCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() {
#Override public TableCell<Person, Person> call(TableColumn<Person, Person> param) {
return new TableCell<Person, Person>() {
#Override protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (this.getTableRow() != null && item != null) {
setText(this.getTableRow().getIndex()+"");
} else {
setText("");
}
}
};
}
});
numberCol.setSortable(false);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
table.setItems(data);
table.getColumns().addAll(numberCol, firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
In java 8 it can be done even easier with lambda expression:
TableColumn<Person, Number> indexColumn = new TableColumn<Person, Number>("#");
indexColumn.setSortable(false);
indexColumn.setCellValueFactory(column-> new ReadOnlyObjectWrapper<Number>(YourTable.getItems().indexOf(column.getValue())));
This is a universal (Generic) cell factory you can simply use anywhere:
public class LineNumbersCellFactory<T, E> implements Callback<TableColumn<T, E>, TableCell<T, E>> {
public LineNumbersCellFactory() {
}
#Override
public TableCell<T, E> call(TableColumn<T, E> param) {
return new TableCell<T, E>() {
#Override
protected void updateItem(E item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setText(this.getTableRow().getIndex() + 1 + "");
} else {
setText("");
}
}
};
}
}
Usage: colRowNum.setCellFactory(new LineNumbersCellFactory());
Delete the +1 if you need 0-indexed rows.
EDIT: Added else block when deleting items
A simple approach that doesn't depend on indexOf(item) or on updateItem() (which may or may not be the only event you would need to listen to) is to bind the text property of the TableCell to its row index:
TableColumn<S, Integer> indexColumn = new TableColumn<>();
indexColumn.setCellFactory(col -> {
TableCell<S, Integer> indexCell = new TableCell<>();
ReadOnlyObjectProperty<TableRow<S>> rowProperty = indexCell.tableRowProperty();
ObjectBinding<String> rowBinding = Bindings.createObjectBinding(() -> {
TableRow<S> row = rowProperty.get();
if (row != null) { // can be null during CSS processing
int rowIndex = row.getIndex();
if (rowIndex < row.getTableView().getItems().size()) {
return Integer.toString(rowIndex);
}
}
return null;
}, rowProperty);
indexCell.textProperty().bind(rowBinding);
return indexCell;
});
If you don't care whether or not rows contain data, you can remove the rowIndex < ...size() check:
TableRow<S> row = rowProperty.get();
return row == null ? null : Integer.toString(row.getIndex());