Last active
January 18, 2016 22:37
-
-
Save james-d/7912548 to your computer and use it in GitHub Desktop.
JavaFX 8 version of https://gist.github.com/james-d/7813134, taking advantage of pseudoclasses.
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
@CHARSET "UTF-8"; | |
.table-row-cell:highlighted { | |
-fx-background-color: brown; | |
-fx-background-insets: 0, 1, 2; | |
-fx-background: -fx-accent; | |
-fx-text-fill: -fx-selection-bar-text; | |
} |
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 javafx.application.Application; | |
import javafx.beans.binding.Bindings; | |
import javafx.beans.property.SimpleStringProperty; | |
import javafx.beans.property.StringProperty; | |
import javafx.collections.FXCollections; | |
import javafx.collections.ObservableList; | |
import javafx.geometry.Insets; | |
import javafx.geometry.Pos; | |
import javafx.scene.Scene; | |
import javafx.scene.control.Button; | |
import javafx.scene.control.ContextMenu; | |
import javafx.scene.control.Label; | |
import javafx.scene.control.MenuItem; | |
import javafx.scene.control.SelectionMode; | |
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.HBox; | |
import javafx.scene.layout.VBox; | |
import javafx.scene.text.Font; | |
import javafx.stage.Stage; | |
public class HighlightingTableViewSample extends Application { | |
private final TableView<Person> table = new TableView<>(); | |
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) { | |
final Label label = new Label("Address Book"); | |
label.setFont(new Font("Arial", 20)); | |
table.setEditable(true); | |
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")); | |
table.setItems(data); | |
table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol)); | |
final StyleChangingRowFactory<Person> rowFactory = new StyleChangingRowFactory<>("highlighted"); | |
table.setRowFactory(rowFactory); | |
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); | |
final Button highlightButton = new Button("Highlight"); | |
highlightButton.disableProperty().bind(Bindings.isEmpty(table.getSelectionModel().getSelectedIndices())); | |
highlightButton.setOnAction(event -> rowFactory.getStyledRowIndices().setAll(table.getSelectionModel().getSelectedIndices()) ); | |
final Button clearHighlightButton = new Button("Clear Highlights"); | |
clearHighlightButton.disableProperty().bind(Bindings.isEmpty(rowFactory.getStyledRowIndices())); | |
clearHighlightButton.setOnAction(event -> rowFactory.getStyledRowIndices().clear() ); | |
final HBox buttons = new HBox(5); | |
buttons.setAlignment(Pos.CENTER); | |
buttons.getChildren().addAll(highlightButton, clearHighlightButton); | |
final VBox vbox = new VBox(); | |
vbox.setSpacing(5); | |
vbox.setPadding(new Insets(10, 0, 0, 10)); | |
vbox.getChildren().addAll(label, table, buttons); | |
Scene scene = new Scene(vbox, 450, 500); | |
stage.setTitle("Highlighting Table View Sample"); | |
scene.getStylesheets().add(getClass().getResource("highlightingTable.css").toExternalForm()); | |
stage.setScene(scene); | |
stage.show(); | |
} | |
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 final StringProperty lastNameProperty() { | |
return lastName ; | |
} | |
public final String getEmail() { | |
return email.get(); | |
} | |
public final void setEmail(String fName) { | |
email.set(fName); | |
} | |
public final StringProperty emailProperty() { | |
return email ; | |
} | |
} | |
} |
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 javafx.collections.FXCollections; | |
import javafx.collections.ListChangeListener.Change; | |
import javafx.collections.ObservableList; | |
import javafx.css.PseudoClass; | |
import javafx.scene.control.TableRow; | |
import javafx.scene.control.TableView; | |
import javafx.util.Callback; | |
/** | |
* A factory for <code>TableRow</code>s suitable for passing to | |
* <code>TableView.setRowFactory(...)</code>. This row factory will | |
* set a pseudoclass state to true for rows whose indices are contained in | |
* <code>getStyledRowIndices</code>. | |
* Modifications to the <code>ObservableList<Integer></code> | |
* returned from <code>getStyledRowIndices</code> will result in | |
* immediate updates to the pseudoclass state of rows added to or removed | |
* from the list. | |
* The pseudoclass is determined | |
* by the <code>styleClass</code> parameter in the constructor. | |
* <br/> | |
* Usage example: | |
* <br/> | |
* <pre> | |
* final TableView<MyDomainObject> table = ... ; | |
* final StyleChangingRowFactory<MyDomainObject> rowFactory | |
* = new StyleChangingRowFactory<>("highlighted"); | |
* table.setRowFactory(rowFactory); | |
* | |
* Button highlightButton = new Button("Highlight selected rows"); | |
* highlightButton.setOnAction(new EventHandler<ActionEvent>() { | |
* @Override | |
* public void handle(ActionEvent event) { | |
* rowFactory().getStyledRowIndices() | |
* .setAll(table.getSelectionModel().getSelectedIndices()); | |
* } | |
* }); | |
* </pre> | |
* | |
* @author James_D | |
* | |
* @param <T> The type of the data displayed in the table row. | |
*/ | |
public class StyleChangingRowFactory<T> implements | |
Callback<TableView<T>, TableRow<T>> { | |
private final PseudoClass pseudoClass ; | |
private final ObservableList<Integer> styledRowIndices ; | |
private final Callback<TableView<T>, TableRow<T>> baseFactory ; | |
/** | |
* Construct a <code>StyleChangingRowFactory</code>, | |
* specifying the name of the pseudoclass that will be set | |
* for rows determined by <code>getStyledRowIndices</code> | |
* and a base factory to create the <code>TableRow</code>. If <code>baseFactory</code> | |
* is <code>null</code>, default table rows will be created. | |
* @param styleClass The name of the pseudoclass that will be set for specified rows. | |
* @param baseFactory A factory for creating the rows. If null, default | |
* <code>TableRow<T></code>s will be created using the default <code>TableRow</code> constructor. | |
*/ | |
public StyleChangingRowFactory(String styleClass, Callback<TableView<T>, TableRow<T>> baseFactory) { | |
this.pseudoClass = PseudoClass.getPseudoClass(styleClass); | |
this.baseFactory = baseFactory ; | |
this.styledRowIndices = FXCollections.observableArrayList(); | |
} | |
/** | |
* Construct a <code>StyleChangingRowFactory</code>, | |
* which sets the pseudoclass <code>styleClass</code> to true for rows determined by | |
* <code>getStyledRowIndices</code>, and using default <code>TableRow</code>s. | |
* @param styleClass | |
*/ | |
public StyleChangingRowFactory(String styleClass) { | |
this(styleClass, null); | |
} | |
@Override | |
public TableRow<T> call(TableView<T> tableView) { | |
final TableRow<T> row ; | |
if (baseFactory == null) { | |
row = new TableRow<>(); | |
} else { | |
row = baseFactory.call(tableView); | |
} | |
styledRowIndices.addListener((Change<? extends Integer> change) | |
-> row.pseudoClassStateChanged(pseudoClass, styledRowIndices.contains(row.getIndex())) | |
); | |
row.indexProperty().addListener((observable, oldValue, newValue) | |
-> row.pseudoClassStateChanged(pseudoClass, styledRowIndices.contains(row.getIndex())) | |
); | |
return row; | |
} | |
/** | |
* | |
* @return The list of indices of the rows for which the pseudoclass <code>styleClass</code> will be set. | |
* Changes to the content of this list will result in the pseudoclass state being immediately updated | |
* on rows whose indices are either added to or removed from this list. | |
*/ | |
public ObservableList<Integer> getStyledRowIndices() { | |
return styledRowIndices ; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice example, but is there way to ensure that the highlighting moves with the row when the table is sorted?