Created
June 12, 2014 11:38
-
-
Save james-d/523831d5921fbe15824d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.table-row-cell:new { | |
-fx-background-color: darkseagreen ; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.util.List; | |
import java.util.function.Function; | |
import javafx.animation.PauseTransition; | |
import javafx.application.Application; | |
import javafx.beans.binding.Bindings; | |
import javafx.beans.binding.BooleanBinding; | |
import javafx.beans.property.ObjectProperty; | |
import javafx.beans.property.Property; | |
import javafx.beans.property.SimpleObjectProperty; | |
import javafx.beans.property.SimpleStringProperty; | |
import javafx.beans.property.StringProperty; | |
import javafx.collections.ListChangeListener.Change; | |
import javafx.collections.ObservableList; | |
import javafx.css.PseudoClass; | |
import javafx.geometry.HPos; | |
import javafx.geometry.Pos; | |
import javafx.scene.Scene; | |
import javafx.scene.control.Button; | |
import javafx.scene.control.Label; | |
import javafx.scene.control.TableColumn; | |
import javafx.scene.control.TableRow; | |
import javafx.scene.control.TableView; | |
import javafx.scene.control.TextField; | |
import javafx.scene.layout.BorderPane; | |
import javafx.scene.layout.ColumnConstraints; | |
import javafx.scene.layout.GridPane; | |
import javafx.scene.layout.HBox; | |
import javafx.scene.layout.Priority; | |
import javafx.stage.Stage; | |
import javafx.util.Duration; | |
public class HighlightNewTableRows extends Application { | |
@Override | |
public void start(Stage primaryStage) { | |
TableView<Person> table = new TableView<>(); | |
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") | |
); | |
table.getColumns().addAll(Arrays.asList( | |
createTableColumn("First Name", Person::firstNameProperty, 150), | |
createTableColumn("Last Name", Person::lastNameProperty, 150), | |
createTableColumn("Email", Person::emailProperty, 150) | |
)); | |
BorderPane newPersonPane = createEditor(table.getItems()); | |
final Duration timeToGetOld = Duration.seconds(1.0); | |
final ObjectProperty<Person> recentlyAddedPerson = new SimpleObjectProperty<>(); | |
table.getItems().addListener((Change<? extends Person> change) -> { | |
while (change.next()) { | |
if (change.wasAdded()) { | |
List<? extends Person> addedPeople = change.getAddedSubList(); | |
Person lastAddedPerson = addedPeople.get(addedPeople.size()-1); | |
recentlyAddedPerson.set(lastAddedPerson); | |
// set back to null after a short delay, unless changed since then: | |
PauseTransition agingTime = new PauseTransition(timeToGetOld); | |
agingTime.setOnFinished(event -> { | |
if (recentlyAddedPerson.get() == lastAddedPerson) { | |
recentlyAddedPerson.set(null); | |
} | |
}); | |
agingTime.play(); | |
} | |
} | |
}); | |
final PseudoClass newPersonPseudoClass = PseudoClass.getPseudoClass("new"); | |
table.setRowFactory(tableView -> new TableRow<Person>() { | |
// Bindings API uses weak listeners, so this needs to be a field to | |
// make sure it stays in scope as long as the TableRow is in scope. | |
private final BooleanBinding itemIsNewPerson | |
= Bindings.isNotNull(itemProperty()) | |
.and(Bindings.equal(itemProperty(), recentlyAddedPerson)); | |
{ | |
// anonymous constructor: | |
itemIsNewPerson.addListener((obs, wasNew, isNew) | |
-> pseudoClassStateChanged(newPersonPseudoClass, isNew)); | |
} | |
}); | |
BorderPane root = new BorderPane(); | |
root.setCenter(table); | |
root.setBottom(newPersonPane); | |
Scene scene = new Scene(root,600,400); | |
scene.getStylesheets().add(getClass().getResource("highlight-new-table-rows.css").toExternalForm()); | |
primaryStage.setScene(scene); | |
primaryStage.show(); | |
} | |
private BorderPane createEditor(ObservableList<Person> items) { | |
GridPane newPersonEditor = new GridPane(); | |
TextField firstNameTF = new TextField(); | |
TextField lastNameTF = new TextField(); | |
TextField emailTF = new TextField(); | |
newPersonEditor.addRow(0, new Label("First Name:"), firstNameTF); | |
newPersonEditor.addRow(1, new Label("Last Name:"), lastNameTF); | |
newPersonEditor.addRow(2, new Label("Email Name:"), emailTF); | |
ColumnConstraints leftCol = new ColumnConstraints(); | |
leftCol.setHalignment(HPos.RIGHT); | |
leftCol.setHgrow(Priority.NEVER); | |
ColumnConstraints rightCol = new ColumnConstraints(); | |
rightCol.setHalignment(HPos.LEFT); | |
rightCol.setHgrow(Priority.ALWAYS); | |
newPersonEditor.getColumnConstraints().addAll(leftCol, rightCol); | |
Button addButton = new Button("Add"); | |
Button clearButton = new Button("Clear"); | |
List<TextField> fields = Arrays.asList(firstNameTF, lastNameTF, emailTF); | |
clearButton.setOnAction(event -> fields.forEach(TextField::clear)); | |
addButton.setOnAction(event -> { | |
items.add(new Person(firstNameTF.getText(), lastNameTF.getText(), emailTF.getText())); | |
fields.forEach(TextField::clear); | |
}); | |
HBox buttons = new HBox(5, addButton, clearButton); | |
buttons.setAlignment(Pos.CENTER); | |
return new BorderPane(newPersonEditor, null, null, buttons, null); | |
} | |
private <S,T> TableColumn<S, T> createTableColumn(String title, Function<S, Property<T>> accessor, double width) { | |
TableColumn<S, T> col = new TableColumn<>(title); | |
col.setCellValueFactory(data -> accessor.apply(data.getValue())); | |
col.setPrefWidth(width); | |
return col ; | |
} | |
public static class Person { | |
private final StringProperty firstName; | |
private final StringProperty lastName; | |
private final StringProperty email; | |
private Person(String fName, String lName, String email) { | |
this.firstName = new SimpleStringProperty(this, "firstName", fName); | |
this.lastName = new SimpleStringProperty(this, "lastName", lName); | |
this.email = new SimpleStringProperty(this, "email", email); | |
} | |
public final String getFirstName() { | |
return firstName.get(); | |
} | |
public final void setFirstName(String fName) { | |
firstName.set(fName); | |
} | |
public StringProperty firstNameProperty() { | |
return firstName ; | |
} | |
public final String getLastName() { | |
return lastName.get(); | |
} | |
public final void setLastName(String fName) { | |
lastName.set(fName); | |
} | |
public StringProperty lastNameProperty() { | |
return lastName ; | |
} | |
public final String getEmail() { | |
return email.get(); | |
} | |
public final void setEmail(String fName) { | |
email.set(fName); | |
} | |
public StringProperty emailProperty() { | |
return email ; | |
} | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment