-
Bug
-
Resolution: Incomplete
-
P3
-
None
-
8u40, 8u45
I'm trying to customize TreeTableView by extending the TreeTableView and overriding the Row skin.
At first when I run the application all skins are created for each row according to its index
( Index 0 RowSkin0, index 1 RowSkin1 ,... ) however after expanding the and collapsing some nodes in the tree table and repeating it for 50 times a new trailing row is created and the skins start to rotate over the index, which is messing the behavior of the treetable ( Index 0 NewRowSkin, index 1 RowSkin0, Index 2 RowSkin1,....). it starts flashing while expanding/collapsing.
Note that at this stage every expand/collapse will change the order of the row skin.
e.g after 1 expand/collapse operation the map become ( index 0 LastRowSkin, index 1 newRowSkin, index 2 RowSkin0, index 3 RowSkin 1, ... ) and so on.
- this behavior is noticed in JDK 1.8 u 40 and above.
- this behavior is not found in JDK 1.8 u 25.
- also this behavior is ONLY noticed when applying the css , to be specific its ONLY noticed when adding
padding to the cell :
.tree-table-view .tree-table-cell{
-fx-border-width:0 0 0 0;
-fx-padding : 16 0 16 0 ;
}
Below is the code and CSS used:
import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Skin;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import com.sun.javafx.scene.control.skin.TreeTableRowSkin;
public class Demo extends Application {
final TreeItem<User> root = new TreeItem<>(new User("Sales Department", "23"));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
root.getChildren().add(new TreeItem<>(new User("Sales Department1", "23")));
TreeItem<User> root1 = new TreeItem<>(new User("Sales Department2", "24"));
root.getChildren().add(root1);
root1.getChildren().add(new TreeItem<>(new User("Sales Department3", "25")));
root.getChildren().add(new TreeItem<>(new User("Sales Department4", "22")));
TreeItem<User> root2 = new TreeItem<>(new User("Sales Department5", "20"));
root.getChildren().add(root2);
root2.getChildren().add(new TreeItem<>(new User("Sales Department6", "21")));
TreeTableColumn<User, String> empColumn =
new TreeTableColumn<>("User");
empColumn.setPrefWidth(150);
empColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<User, String> param) ->
new ReadOnlyStringWrapper(param.getValue().getValue().userName));
TreeTableColumn<User, String> ageColumn =
new TreeTableColumn<>("Age");
ageColumn.setPrefWidth(150);
ageColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<User, String> param) ->
new ReadOnlyStringWrapper(param.getValue().getValue().age));
CustomTreeTableView<User> treeView = new CustomTreeTableView<User>(root);
treeView.setShowRoot(false);
treeView.getColumns().setAll(empColumn, ageColumn);
StackPane main = new StackPane();
main.setPadding(new Insets(10));
main.getChildren().add(treeView);
Scene scene = new Scene(main, 600, 400);
scene.getStylesheets().add(Demo.class.getResource("css/styles.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
class User {
String userName;
String age;
public User(String userName, String age) {
this.userName = userName;
this.age = age;
}
}
private class CustomTreeTableView<S> extends TreeTableView<S> {
public CustomTreeTableView(TreeItem<S> root) {
super(root);
this.setRowFactory(new Callback<TreeTableView<S>, TreeTableRow<S>>() {
@Override
public TreeTableRow<S> call(TreeTableView<S> param) {
return new CustomTreeTableRow<S>();
}
});
}
}
private class CustomTreeTableRow<T> extends TreeTableRow<T> {
@Override protected Skin<?> createDefaultSkin() {
return new CustomTreeTableRowSkin<T>(this);
}
}
private class CustomTreeTableRowSkin<T> extends TreeTableRowSkin<T> {
public CustomTreeTableRowSkin(TreeTableRow<T> control) {
super(control);
System.out.println("Row Skin " + getSkinnable().getIndex() + " is created");
}
@Override
protected void layoutChildren(final double x, final double y, final double w, final double h) {
super.layoutChildren(x, y, w, h);
System.out.println("ROW : " + getSkinnable().getIndex()+ " : " + CustomTreeTableRowSkin.this);
}
}
}
/*
* TREE TABLE CSS
*/
.tree-table-view{
-fx-tree-table-color: rgba(255, 0, 0, 0.2);
-fx-tree-table-rippler-color : rgba(255, 0, 0, 0.4);
}
.tree-table-view:focused .tree-table-row-cell:selected {
-fx-background-color: -fx-tree-table-color ;
-fx-table-cell-border-color: -fx-tree-table-color;
-fx-text-fill: BLACK;
}
.tree-table-view:focused .tree-table-row-cell:selected .tree-table-cell{
-fx-text-fill: BLACK;
}
.tree-table-view .c3d-rippler {
-fx-rippler-fill: -fx-tree-table-rippler-color;
}
.tree-table-view .column-header ,
.tree-table-view .column-header-background,
.tree-table-view .column-header-background .filler{
-fx-background-color:TRANSPARENT;
}
.tree-table-view .column-header{
-fx-border-width : 0 1 0 1;
-fx-border-color: #F3F3F3;
}
.tree-table-view .column-header .label {
-fx-text-fill : #949494;
-fx-padding : 16 0 16 0 ;
}
.tree-table-view .column-header .arrow {
-fx-background-color : #949494;
}
.tree-table-view .column-header:last-visible {
-fx-border-width: 0 2 0 1;
}
.tree-table-view .column-header-background{
-fx-border-width : 0 0.0 1 0;
-fx-border-color:#F3F3F3;
}
.tree-table-view .tree-table-cell{
-fx-border-width:0 0 0 0;
-fx-padding : 16 0 16 0 ;
}
.tree-table-view .column-overlay{
-fx-background-color: -fx-tree-table-color;
}
.tree-table-view .column-resize-line, .tree-table-view .column-drag-header{
-fx-background-color: -fx-tree-table-rippler-color;
}
.tree-table-view:focused {
-fx-background-color: -fx-tree-table-color,-fx-box-border,-fx-control-inner-background;
-fx-background-insets: -1.4, 0, 1;
-fx-background-radius: 1.4, 0, 0;
/*....*/
-fx-padding: 1; /* 0.083333em; */
}
.tree-table-row-cell > .tree-disclosure-node > .arrow {
-fx-background-color: -fx-text-fill;
-fx-padding: 0.333333em 0.229em 0.333333em 0.229em; /* 4 */
-fx-shape: "M 0 -3.5 L 4 0 L 0 3.5 z";
}
At first when I run the application all skins are created for each row according to its index
( Index 0 RowSkin0, index 1 RowSkin1 ,... ) however after expanding the and collapsing some nodes in the tree table and repeating it for 50 times a new trailing row is created and the skins start to rotate over the index, which is messing the behavior of the treetable ( Index 0 NewRowSkin, index 1 RowSkin0, Index 2 RowSkin1,....). it starts flashing while expanding/collapsing.
Note that at this stage every expand/collapse will change the order of the row skin.
e.g after 1 expand/collapse operation the map become ( index 0 LastRowSkin, index 1 newRowSkin, index 2 RowSkin0, index 3 RowSkin 1, ... ) and so on.
- this behavior is noticed in JDK 1.8 u 40 and above.
- this behavior is not found in JDK 1.8 u 25.
- also this behavior is ONLY noticed when applying the css , to be specific its ONLY noticed when adding
padding to the cell :
.tree-table-view .tree-table-cell{
-fx-border-width:0 0 0 0;
-fx-padding : 16 0 16 0 ;
}
Below is the code and CSS used:
import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Skin;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import com.sun.javafx.scene.control.skin.TreeTableRowSkin;
public class Demo extends Application {
final TreeItem<User> root = new TreeItem<>(new User("Sales Department", "23"));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
root.getChildren().add(new TreeItem<>(new User("Sales Department1", "23")));
TreeItem<User> root1 = new TreeItem<>(new User("Sales Department2", "24"));
root.getChildren().add(root1);
root1.getChildren().add(new TreeItem<>(new User("Sales Department3", "25")));
root.getChildren().add(new TreeItem<>(new User("Sales Department4", "22")));
TreeItem<User> root2 = new TreeItem<>(new User("Sales Department5", "20"));
root.getChildren().add(root2);
root2.getChildren().add(new TreeItem<>(new User("Sales Department6", "21")));
TreeTableColumn<User, String> empColumn =
new TreeTableColumn<>("User");
empColumn.setPrefWidth(150);
empColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<User, String> param) ->
new ReadOnlyStringWrapper(param.getValue().getValue().userName));
TreeTableColumn<User, String> ageColumn =
new TreeTableColumn<>("Age");
ageColumn.setPrefWidth(150);
ageColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<User, String> param) ->
new ReadOnlyStringWrapper(param.getValue().getValue().age));
CustomTreeTableView<User> treeView = new CustomTreeTableView<User>(root);
treeView.setShowRoot(false);
treeView.getColumns().setAll(empColumn, ageColumn);
StackPane main = new StackPane();
main.setPadding(new Insets(10));
main.getChildren().add(treeView);
Scene scene = new Scene(main, 600, 400);
scene.getStylesheets().add(Demo.class.getResource("css/styles.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
class User {
String userName;
String age;
public User(String userName, String age) {
this.userName = userName;
this.age = age;
}
}
private class CustomTreeTableView<S> extends TreeTableView<S> {
public CustomTreeTableView(TreeItem<S> root) {
super(root);
this.setRowFactory(new Callback<TreeTableView<S>, TreeTableRow<S>>() {
@Override
public TreeTableRow<S> call(TreeTableView<S> param) {
return new CustomTreeTableRow<S>();
}
});
}
}
private class CustomTreeTableRow<T> extends TreeTableRow<T> {
@Override protected Skin<?> createDefaultSkin() {
return new CustomTreeTableRowSkin<T>(this);
}
}
private class CustomTreeTableRowSkin<T> extends TreeTableRowSkin<T> {
public CustomTreeTableRowSkin(TreeTableRow<T> control) {
super(control);
System.out.println("Row Skin " + getSkinnable().getIndex() + " is created");
}
@Override
protected void layoutChildren(final double x, final double y, final double w, final double h) {
super.layoutChildren(x, y, w, h);
System.out.println("ROW : " + getSkinnable().getIndex()+ " : " + CustomTreeTableRowSkin.this);
}
}
}
/*
* TREE TABLE CSS
*/
.tree-table-view{
-fx-tree-table-color: rgba(255, 0, 0, 0.2);
-fx-tree-table-rippler-color : rgba(255, 0, 0, 0.4);
}
.tree-table-view:focused .tree-table-row-cell:selected {
-fx-background-color: -fx-tree-table-color ;
-fx-table-cell-border-color: -fx-tree-table-color;
-fx-text-fill: BLACK;
}
.tree-table-view:focused .tree-table-row-cell:selected .tree-table-cell{
-fx-text-fill: BLACK;
}
.tree-table-view .c3d-rippler {
-fx-rippler-fill: -fx-tree-table-rippler-color;
}
.tree-table-view .column-header ,
.tree-table-view .column-header-background,
.tree-table-view .column-header-background .filler{
-fx-background-color:TRANSPARENT;
}
.tree-table-view .column-header{
-fx-border-width : 0 1 0 1;
-fx-border-color: #F3F3F3;
}
.tree-table-view .column-header .label {
-fx-text-fill : #949494;
-fx-padding : 16 0 16 0 ;
}
.tree-table-view .column-header .arrow {
-fx-background-color : #949494;
}
.tree-table-view .column-header:last-visible {
-fx-border-width: 0 2 0 1;
}
.tree-table-view .column-header-background{
-fx-border-width : 0 0.0 1 0;
-fx-border-color:#F3F3F3;
}
.tree-table-view .tree-table-cell{
-fx-border-width:0 0 0 0;
-fx-padding : 16 0 16 0 ;
}
.tree-table-view .column-overlay{
-fx-background-color: -fx-tree-table-color;
}
.tree-table-view .column-resize-line, .tree-table-view .column-drag-header{
-fx-background-color: -fx-tree-table-rippler-color;
}
.tree-table-view:focused {
-fx-background-color: -fx-tree-table-color,-fx-box-border,-fx-control-inner-background;
-fx-background-insets: -1.4, 0, 1;
-fx-background-radius: 1.4, 0, 0;
/*....*/
-fx-padding: 1; /* 0.083333em; */
}
.tree-table-row-cell > .tree-disclosure-node > .arrow {
-fx-background-color: -fx-text-fill;
-fx-padding: 0.333333em 0.229em 0.333333em 0.229em; /* 4 */
-fx-shape: "M 0 -3.5 L 4 0 L 0 3.5 z";
}