-
Bug
-
Resolution: Incomplete
-
P4
-
None
-
8u66
-
x86
-
other
FULL PRODUCT VERSION :
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Darwin xxx.fritz.box 15.3.0 Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
Using the TreeView with a Layout/Hierarchy like the following:
TreeView
- A0 (preferedHeight = 40)
-- A1 (preferedHeight = 30)
--- A2 (preferedHeight = 20)
-- B1 (preferedHeight = 30)
--- B2 (preferedHeight = 20)
-- C1 (preferedHeight = 30)
--- C2 (preferedHeight = 20)
... (repeat x-times)
it always happens when you try to scrollTo(index) all of the 0-Level Nodes (assuming you have a larger number ~20) that one of those scrollTo(index) calls does not produces a result where the row ends up at the top. This error does not occur when all rows have the same height.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Create a TreeView with the described hierarchy and layout.
- Try to scrollTo(index) to every index of every top level item.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Every row is positioned at the top. Except for those at the bottom.
ACTUAL -
At least one of those scrollTo(index) will not result in a row being positioned at the top (bottom rows excluded)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
no error, visual bug.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package de.t2med.aps.client.praxis.statistik.karteikontrolle;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class TreeViewExample extends Application {
public static final int MIN_HEIGHT = 1024;
public static final int MIN_WIDTH = 1280;
private final BorderPane rootLayout = new BorderPane();
private List<TreeViewData> data;
private TreeView<TreeViewRowItem> treeView;
private TreeItem<TreeViewRowItem> root;
public static void main(final String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) throws Exception {
Locale.setDefault(Locale.GERMANY);
initData();
initTreeView();
initSelectionView();
final Scene scene = new Scene(rootLayout);
rootLayout.setPrefWidth(MIN_WIDTH);
rootLayout.setPrefHeight(MIN_HEIGHT);
primaryStage.setScene(scene);
primaryStage.setMinWidth(MIN_WIDTH);
primaryStage.setMinHeight(MIN_HEIGHT);
primaryStage.centerOnScreen();
primaryStage.show();
}
private void initData() {
data = new ArrayList<>();
for (int i = 0; i < 25; i++) {
data.add(new TreeViewData(String.format("%s (%s)", RandomStringUtils.randomAlphanumeric(10), String.valueOf(i))));
}
}
private void initSelectionView() {
final ListView<TreeViewData> listView = new ListView<>();
listView.setCellFactory(param -> new ListCell<TreeViewData>() {
@Override
protected void updateItem(final TreeViewData item, final boolean empty) {
super.updateItem(item, empty);
if (null == item) {
setGraphic(null);
} else {
setGraphic(new Label(item.title));
}
}
});
listView.setItems(FXCollections.observableArrayList(data));
listView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
listView.getSelectionModel().getSelectedItems().addListener((ListChangeListener<TreeViewData>) c -> scrollTo(c.getList().get(0)));
rootLayout.setRight(listView);
}
private void initTreeView() {
treeView = new TreeView<>();
treeView.setCellFactory(new Callback<TreeView<TreeViewRowItem>, TreeCell<TreeViewRowItem>>() {
@Override
public TreeCell<TreeViewRowItem> call(final TreeView<TreeViewRowItem> param) {
return new TreeCell<TreeViewRowItem>() {
@Override
protected void updateItem(final TreeViewRowItem item, final boolean empty) {
super.updateItem(item, empty);
if (null == item) {
setGraphic(null);
} else {
final Label value = new Label(item.getText());
switch (item.level) {
case FIRST_LEVEL:
value.setPrefHeight(40.0);
break;
case SECOND_LEVEL:
value.setPrefHeight(30.0);
break;
case THIRD_LEVEL_B:
case THIRD_LEVEL_C:
case THIRD_LEVEL_A:
value.setPrefHeight(20.0);
break;
}
setGraphic(value);
}
}
};
}
});
root = new TreeItem<>();
root.setGraphic(new Label("Root"));
root.setExpanded(true);
treeView.setRoot(root);
treeView.setShowRoot(false);
data.forEach(treeViewData -> {
final TreeItem<TreeViewRowItem> treeItem = new TreeItem<>(new TreeViewRowItem(TreeViewDataType.FIRST_LEVEL, treeViewData, 0));
treeItem.setExpanded(true);
root.getChildren().add(treeItem);
addChildren(treeViewData.childrenA, treeViewData, treeItem, true, TreeViewDataType.THIRD_LEVEL_A);
addChildren(treeViewData.childrenB, treeViewData, treeItem, true, TreeViewDataType.THIRD_LEVEL_B);
addChildren(treeViewData.childrenC, treeViewData, treeItem, false, TreeViewDataType.THIRD_LEVEL_C);
});
rootLayout.setCenter(treeView);
}
private void addChildren(final List<String> list, final TreeViewData treeViewData, final TreeItem<TreeViewRowItem> treeItem, final boolean expanded,
final TreeViewDataType thirdLevel) {
final TreeItem<TreeViewRowItem> headerItem = new TreeItem<>(new TreeViewRowItem(TreeViewDataType.SECOND_LEVEL, treeViewData, 0));
treeItem.getChildren().add(headerItem);
headerItem.setExpanded(expanded);
for (int i = 0; i < list.size(); i++) {
final TreeItem<TreeViewRowItem> child = new TreeItem<>(new TreeViewRowItem(thirdLevel, treeViewData, i));
headerItem.getChildren().add(child);
}
}
private void scrollTo(final TreeViewData treeViewData) {
for (final TreeItem<TreeViewRowItem> item : root.getChildren()) {
if (null != item.getValue() && treeViewData.equals(item.getValue().data)) {
final int row = treeView.getRow(item);
treeView.scrollTo(row);
treeView.getSelectionModel().select(row);
treeView.requestFocus();
}
}
}
private class TreeViewData {
private final String title;
private final List<String> childrenA = new ArrayList<>();
private final List<String> childrenB = new ArrayList<>();
private final List<String> childrenC = new ArrayList<>();
public TreeViewData(final String title) {
this.title = title;
randomChildren(childrenA);
randomChildren(childrenB);
randomChildren(childrenC);
}
private void randomChildren(final List<String> list) {
for (int i = 0; i < RandomUtils.nextInt(2, 8); i++) {
list.add(RandomStringUtils.randomAlphabetic(25));
}
}
}
private class TreeViewRowItem {
final TreeViewDataType level;
final int index;
final TreeViewData data;
public TreeViewRowItem(final TreeViewDataType level, final TreeViewData data, final int index) {
this.level = level;
this.index = index;
this.data = data;
}
public String getText() {
switch (level) {
case FIRST_LEVEL:
return data.title;
case SECOND_LEVEL:
return "Header";
case THIRD_LEVEL_A:
return data.childrenA.get(index);
case THIRD_LEVEL_B:
return data.childrenB.get(index);
case THIRD_LEVEL_C:
return data.childrenC.get(index);
}
return "";
}
}
enum TreeViewDataType {
FIRST_LEVEL,
SECOND_LEVEL,
THIRD_LEVEL_B,
THIRD_LEVEL_C,
THIRD_LEVEL_A
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None found. API too private.
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Darwin xxx.fritz.box 15.3.0 Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
Using the TreeView with a Layout/Hierarchy like the following:
TreeView
- A0 (preferedHeight = 40)
-- A1 (preferedHeight = 30)
--- A2 (preferedHeight = 20)
-- B1 (preferedHeight = 30)
--- B2 (preferedHeight = 20)
-- C1 (preferedHeight = 30)
--- C2 (preferedHeight = 20)
... (repeat x-times)
it always happens when you try to scrollTo(index) all of the 0-Level Nodes (assuming you have a larger number ~20) that one of those scrollTo(index) calls does not produces a result where the row ends up at the top. This error does not occur when all rows have the same height.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Create a TreeView with the described hierarchy and layout.
- Try to scrollTo(index) to every index of every top level item.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Every row is positioned at the top. Except for those at the bottom.
ACTUAL -
At least one of those scrollTo(index) will not result in a row being positioned at the top (bottom rows excluded)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
no error, visual bug.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package de.t2med.aps.client.praxis.statistik.karteikontrolle;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class TreeViewExample extends Application {
public static final int MIN_HEIGHT = 1024;
public static final int MIN_WIDTH = 1280;
private final BorderPane rootLayout = new BorderPane();
private List<TreeViewData> data;
private TreeView<TreeViewRowItem> treeView;
private TreeItem<TreeViewRowItem> root;
public static void main(final String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) throws Exception {
Locale.setDefault(Locale.GERMANY);
initData();
initTreeView();
initSelectionView();
final Scene scene = new Scene(rootLayout);
rootLayout.setPrefWidth(MIN_WIDTH);
rootLayout.setPrefHeight(MIN_HEIGHT);
primaryStage.setScene(scene);
primaryStage.setMinWidth(MIN_WIDTH);
primaryStage.setMinHeight(MIN_HEIGHT);
primaryStage.centerOnScreen();
primaryStage.show();
}
private void initData() {
data = new ArrayList<>();
for (int i = 0; i < 25; i++) {
data.add(new TreeViewData(String.format("%s (%s)", RandomStringUtils.randomAlphanumeric(10), String.valueOf(i))));
}
}
private void initSelectionView() {
final ListView<TreeViewData> listView = new ListView<>();
listView.setCellFactory(param -> new ListCell<TreeViewData>() {
@Override
protected void updateItem(final TreeViewData item, final boolean empty) {
super.updateItem(item, empty);
if (null == item) {
setGraphic(null);
} else {
setGraphic(new Label(item.title));
}
}
});
listView.setItems(FXCollections.observableArrayList(data));
listView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
listView.getSelectionModel().getSelectedItems().addListener((ListChangeListener<TreeViewData>) c -> scrollTo(c.getList().get(0)));
rootLayout.setRight(listView);
}
private void initTreeView() {
treeView = new TreeView<>();
treeView.setCellFactory(new Callback<TreeView<TreeViewRowItem>, TreeCell<TreeViewRowItem>>() {
@Override
public TreeCell<TreeViewRowItem> call(final TreeView<TreeViewRowItem> param) {
return new TreeCell<TreeViewRowItem>() {
@Override
protected void updateItem(final TreeViewRowItem item, final boolean empty) {
super.updateItem(item, empty);
if (null == item) {
setGraphic(null);
} else {
final Label value = new Label(item.getText());
switch (item.level) {
case FIRST_LEVEL:
value.setPrefHeight(40.0);
break;
case SECOND_LEVEL:
value.setPrefHeight(30.0);
break;
case THIRD_LEVEL_B:
case THIRD_LEVEL_C:
case THIRD_LEVEL_A:
value.setPrefHeight(20.0);
break;
}
setGraphic(value);
}
}
};
}
});
root = new TreeItem<>();
root.setGraphic(new Label("Root"));
root.setExpanded(true);
treeView.setRoot(root);
treeView.setShowRoot(false);
data.forEach(treeViewData -> {
final TreeItem<TreeViewRowItem> treeItem = new TreeItem<>(new TreeViewRowItem(TreeViewDataType.FIRST_LEVEL, treeViewData, 0));
treeItem.setExpanded(true);
root.getChildren().add(treeItem);
addChildren(treeViewData.childrenA, treeViewData, treeItem, true, TreeViewDataType.THIRD_LEVEL_A);
addChildren(treeViewData.childrenB, treeViewData, treeItem, true, TreeViewDataType.THIRD_LEVEL_B);
addChildren(treeViewData.childrenC, treeViewData, treeItem, false, TreeViewDataType.THIRD_LEVEL_C);
});
rootLayout.setCenter(treeView);
}
private void addChildren(final List<String> list, final TreeViewData treeViewData, final TreeItem<TreeViewRowItem> treeItem, final boolean expanded,
final TreeViewDataType thirdLevel) {
final TreeItem<TreeViewRowItem> headerItem = new TreeItem<>(new TreeViewRowItem(TreeViewDataType.SECOND_LEVEL, treeViewData, 0));
treeItem.getChildren().add(headerItem);
headerItem.setExpanded(expanded);
for (int i = 0; i < list.size(); i++) {
final TreeItem<TreeViewRowItem> child = new TreeItem<>(new TreeViewRowItem(thirdLevel, treeViewData, i));
headerItem.getChildren().add(child);
}
}
private void scrollTo(final TreeViewData treeViewData) {
for (final TreeItem<TreeViewRowItem> item : root.getChildren()) {
if (null != item.getValue() && treeViewData.equals(item.getValue().data)) {
final int row = treeView.getRow(item);
treeView.scrollTo(row);
treeView.getSelectionModel().select(row);
treeView.requestFocus();
}
}
}
private class TreeViewData {
private final String title;
private final List<String> childrenA = new ArrayList<>();
private final List<String> childrenB = new ArrayList<>();
private final List<String> childrenC = new ArrayList<>();
public TreeViewData(final String title) {
this.title = title;
randomChildren(childrenA);
randomChildren(childrenB);
randomChildren(childrenC);
}
private void randomChildren(final List<String> list) {
for (int i = 0; i < RandomUtils.nextInt(2, 8); i++) {
list.add(RandomStringUtils.randomAlphabetic(25));
}
}
}
private class TreeViewRowItem {
final TreeViewDataType level;
final int index;
final TreeViewData data;
public TreeViewRowItem(final TreeViewDataType level, final TreeViewData data, final int index) {
this.level = level;
this.index = index;
this.data = data;
}
public String getText() {
switch (level) {
case FIRST_LEVEL:
return data.title;
case SECOND_LEVEL:
return "Header";
case THIRD_LEVEL_A:
return data.childrenA.get(index);
case THIRD_LEVEL_B:
return data.childrenB.get(index);
case THIRD_LEVEL_C:
return data.childrenC.get(index);
}
return "";
}
}
enum TreeViewDataType {
FIRST_LEVEL,
SECOND_LEVEL,
THIRD_LEVEL_B,
THIRD_LEVEL_C,
THIRD_LEVEL_A
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None found. API too private.