I have an app that makes significant use of checkboxes in JavaFX TreeView and TableView. There is custom code as much of it was done before the enhancements that came later in JavaFX 2.2.
I now find that checkboxes that used to work do not work (as if they are disabled) although some work intermittently.
I have checked through the Oracle compatibility documentation and I can find nothing relevant.
I have a small sample app that works perfectly in Java 7.4 but shows the same faulty behaviour as the main app in Java 8.
Could anyone you please suggest where I might start looking from your own experience - e.g. cell factory, callback etc - or indicate if anything fundamental changed with this kind of construct at Java 8? I have posted the sample app code below (four separate classes).
Thank you in advance.
package samplefx2_original_v7;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
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.TableColumn.CellEditEvent;
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 SampleFX2_Original_V7 extends Application {
private TableView table = new TableView();
private boolean everything = false;
//Sample data for the table.
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new ControlPerson(false, "Select Columns", false, false),
new Person(true, "Jacob Smith", true, false),
new Person(true, "Isabella Johnson", true, true),
new Person(true, "Ethan Williams", false, false),
new Person(true, "Emma Jones", false, true),
new Person(false, "Michael Brown", true, true));
/**
* @param args the command line arguments
*/
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(850);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
//A custom cell factory that creates checkboxes for a boolean property.
Callback<TableColumn, TableCell> colCheckFactory = new Callback<TableColumn, TableCell>() {
@Override
public TableCell call(TableColumn p) {
return new CheckBoxCell();
}
};
//The various columns
TableColumn nameCol = new TableColumn("Name");
nameCol.setMinWidth(100);
nameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("name"));
TableColumn contactCol = createContactColumn(colCheckFactory);
TableColumn emailCol = createEmailColumn(colCheckFactory);
TableColumn phoneCol = createPhoneColumn(colCheckFactory);
//Add the columns and data to the table.
table.setItems(data);
table.getColumns().addAll(nameCol, contactCol, emailCol, phoneCol);
//Make the table editable
table.setEditable(true);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.getChildren().addAll(label, table);
vbox.setPadding(new Insets(10, 0, 0, 10));
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
private TableColumn createEmailColumn(Callback<TableColumn, TableCell> cellFactory) {
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(75);
emailCol.setCellValueFactory(new PropertyValueFactory("email"));
emailCol.setCellFactory(cellFactory);
emailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, Boolean>>() {
@Override
public void handle(CellEditEvent<Person, Boolean> event) {
if (event.getRowValue() instanceof ControlPerson) {
for (Person p : data) {
p.setEmail(event.getNewValue());
}
} else {
//Need to handle the indivdual cells as well as the special control cells.
Person p = event.getRowValue();
p.setEmail( event.getNewValue() );
}
}
});
return emailCol;
}
private TableColumn createPhoneColumn(Callback<TableColumn, TableCell> cellFactory) {
TableColumn phoneCol = new TableColumn("Phone");
phoneCol.setMinWidth(75);
phoneCol.setCellValueFactory( new PropertyValueFactory("phone"));
phoneCol.setCellFactory(cellFactory);
phoneCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, Boolean>>() {
@Override
public void handle(CellEditEvent<Person, Boolean> event) {
if (event.getRowValue() instanceof ControlPerson) {
for (Person p : data) {
p.setPhone(event.getNewValue());
}
} else {
Person p = event.getRowValue();
p.setPhone( event.getNewValue() );
}
}
});
return phoneCol;
}
/**
* This is the main control column in your application (containing the green and red circles).
*
* @param cellFactory
* @return
*/
private TableColumn createContactColumn( Callback<TableColumn, TableCell> cellFactory ) {
TableColumn contactCol = new TableColumn("Contact");
contactCol.setMinWidth(75);
contactCol.setCellValueFactory( new PropertyValueFactory( "contact"));
contactCol.setCellFactory(cellFactory);
contactCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, Boolean>>() {
@Override
public void handle(CellEditEvent<Person, Boolean> event) {
//This handler is different to the other two as it controls the checking/unchecking of both
//the whole table and individual rows.
if (event.getRowValue() instanceof ControlPerson) {
for (Person p : data) {
p.setContact(event.getNewValue());
p.setEmail(event.getNewValue());
p.setPhone(event.getNewValue());
}
//This is just an example of how you would control a special "everything" flag.
//You could call any method or take any action here to deal with the special
//case where everything is selected.
everything = event.getNewValue();
} else {
//Set the state of any boolean properties to modify the whole row.
Person p = event.getRowValue();
p.setContact( event.getNewValue() );
p.setEmail(event.getNewValue());
p.setPhone(event.getNewValue());
}
}
});
return contactCol;
}
}
package samplefx2_original_v7;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private final SimpleBooleanProperty contact;
private final SimpleStringProperty name;
private final SimpleBooleanProperty email;
private final SimpleBooleanProperty phone;
public Person(boolean contact, String name, boolean email, boolean phone) {
this.contact = new SimpleBooleanProperty( contact );
this.name = new SimpleStringProperty(name);
this.email = new SimpleBooleanProperty( email );
this.phone = new SimpleBooleanProperty( phone );
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public SimpleStringProperty nameProperty() {
return name;
}
public boolean isContact() {
return contact.get();
}
public void setContact( boolean contact ) {
this.contact.set( contact );
}
public SimpleBooleanProperty contactProperty() {
return contact;
}
public boolean isEmail() {
return email.get();
}
public void setEmail( boolean email ) {
this.email.set( email );
}
public SimpleBooleanProperty emailProperty() {
return email;
}
public boolean isPhone() {
return contact.get();
}
public void setPhone( boolean phone ) {
this.phone.set( phone );
}
public SimpleBooleanProperty phoneProperty() {
return phone;
}
}
package samplefx2_original_v7;
/**
* This subclass of Person is used only to identify the row(s) that is used to control
* the checking and unchecking of columns.
*/
public class ControlPerson extends Person {
public ControlPerson(boolean active, String name, boolean email, boolean phone) {
super(active, name, email, phone);
}
}
package samplefx2_original_v7;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
public class CheckBoxCell extends TableCell<Person, Boolean> {
private CheckBox checkBox;
public CheckBoxCell() {
if (checkBox == null) {
checkBox = new CheckBox();
checkBox.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
CheckBox cb = (CheckBox) event.getSource();
getTableView().edit(getTableRow().getIndex(), getTableColumn());
commitEdit(cb.isSelected());
}
});
}
setGraphic(checkBox);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
//Center align the checkboxes.
setAlignment(Pos.CENTER);
}
@Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
//If we don't have an item don't draw the checkbox.
setGraphic( null );
// checkBox.setDisable(true);
// checkBox.setSelected(false);
} else {
checkBox.setDisable(false);
checkBox.setSelected(item);
}
}
}
Aucun commentaire:
Enregistrer un commentaire