Manually expand/collapse all treeitems memory cost javafx 2.2 - java

I am developing a JavaFX 2.2 application using Netbeans 7.2. I am working with a treeview and I extended TreeCell to provide to each TreeItem a context-menu with a MenuItem with "Collpase All" functionality. The max depth level of the treeview is 4. When a user right clicks on a TreeItem of level 2 and clicks to "Collapse All" MenuItem i want to make all the TreeItems of level 3 collapsed (setExpanded(false)). Below you can see the code that I am using. My problem is the memory and CPU cost of this operation. I inserted 250 TreeItems to level 3. The cost of a collapse all operation was ~200MB of memory on each collapseAll click and spends about 2s of time! My developer computer's CPU is an Intel i5 (3.3GHz) and I have 8GB of memory. Is this numbers of hardware cost normal or I am doing something wrong in my code? Am I using a wrong way to collapse them?
This class manages the TreeView. Loads data from database, reloads them, knows the selected TreeItem and expand/collapse the selected children TreeItems.
public final class TargetTree extends SqlConnectionManager {
private TreeView tree;
private TreeItem selectedItem;
private TargetTree() {
super();
this.tree = null;
this.selectedItem = null;
}
private TargetTree(TreeView tree) {
super();
this.tree = tree;
this.selectedItem = null;
}
public static TargetTree construct(TreeView tree) {
if (tree == null) {
return null;
}
TargetTree targetTree = new TargetTree(tree);
targetTree.load();
return targetTree;
}
public void reload() {
// Clear current tree.
if (tree.getRoot() != null) {
for (int i = 0; i < tree.getRoot().getChildren().size(); i++) {
tree.getRoot().getChildren().clear();
}
tree.setRoot(null);
}
this.load();
}
public void prune() {
//TODO
}
private void load() {
// New root Item.
final TreeItem<Object> treeRoot = new TreeItem<>((Object) "Root");
treeRoot.setExpanded(true);
// This integers help to find when to build a new department/section/measure.
int lastDepartmentId = -1;
int lastSectionId = -1;
int lastMeasureId = -1;
int lastTargetId = -1;
//The temp treeitems.
TreeItem<Object> departmentTreeItem = null;
TreeItem<Object> sectionTreeItem = null;
TreeItem<Object> measureTreeItem = null;
TreeItem<Object> targetTreeItem = null;
// Get the new TreeItems from the database.
super.errorMessage = "";
try {
// Establishing connection with db.
super.openConnection();
// Query to be executed. Selects everything from the database.
preparedStmt = connection.prepareStatement(
"SELECT.....ORDER BY....;");
resultSet = preparedStmt.executeQuery();
while (resultSet.next()) {
// Department Creation.
if (lastDepartmentId != resultSet.getInt("departmentId")) {
final Department department = Department.initEmpty();
department.setId(resultSet.getInt("departmentId"));
department.setName(resultSet.getString("departmentName"));
// Create the treeitem for this department.
departmentTreeItem = new TreeItem<>((Object) department);
departmentTreeItem.setExpanded(true);
treeRoot.getChildren().add(departmentTreeItem);
// Reset the children ids to ensure that they will be recreated.
lastDepartmentId = resultSet.getInt("departmentId");
lastSectionId = -1;
lastMeasureId = -1;
lastTargetId = -1;
}
// Section Creation.
if (lastSectionId != resultSet.getInt("sectionId")) {
final Section section = Section.initEmpty();
section.setId(resultSet.getInt("sectionId"));
section.setName(resultSet.getString("sectionName"));
// Create the treeitem for this section.
sectionTreeItem = new TreeItem<>((Object) section);
sectionTreeItem.setExpanded(true);
departmentTreeItem.getChildren().add(sectionTreeItem);
// Reset the children ids to ensure that they will be recreated.
lastSectionId = resultSet.getInt("sectionId");
lastMeasureId = -1;
lastTargetId = -1;
}
// Measure Creation.
if (lastMeasureId != resultSet.getInt("measureId")) {
final Measure measure = Measure.initEmpty();
measure.setId(resultSet.getInt("measureId"));
measure.setLastname(resultSet.getString("measureLastname"));
measure.setFirstname(resultSet.getString("measureFirstName"));
// Create the treeitem for this measure.
measureTreeItem = new TreeItem<>((Object) measure);
measureTreeItem.setExpanded(true);
sectionTreeItem.getChildren().add(measureTreeItem );
// Reset the children ids to ensure that they will be recreated.
lastMeasureId = resultSet.getInt("measureId");
lastTargetId = -1;
}
// Target Creation.
if (lastTargetId != resultSet.getInt("targetId")) {
final Target target = Target.initEmpty();
target.setId(resultSet.getInt("targetId"));
target.setText(resultSet.getString("targetText"));
// Create the treeitem for this target.
targetTreeItem = new TreeItem<>((Object) target);
targetTreeItem.setExpanded(false);
measureTreeItem.getChildren().add(targetTreeItem);
// Reset the children ids to ensure that they will be recreated.
lastTargetId = resultSet.getInt("targetId");
}
}
closeAll();
} catch (SQLException ex) {
super.errorMessage = ex.getMessage();
}
tree.setRoot(treeRoot);
final TargetTree targetTree = this;
tree.setCellFactory(new Callback<TreeView<Object>, TreeCell<Object>>() {
#Override
public TreeCell<Object> call(TreeView<Object> p) {
return new TargetTreeCell(targetTree);
}
});
// Select a Tree Item.
tree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
selectedItem = (TreeItem) newValue;
}
});
}
public void collapseChildren() {
Thread thread = new Thread(new Task<Void>() {
#Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
#Override
public void run() {
for (int i = 0; i < selectedItem.getChildren().size(); i++) {
TreeItem<Object> current = (TreeItem<Object>) selectedItem.getChildren().get(i);
if (!current.isLeaf()) {
current.setExpanded(false);
}
current = null;
}
selectedItem.setExpanded(false);
System.gc();
}
});
return null;
}
});
thread.setDaemon(true);
thread.start();
}
public void expandChildren() {
Thread thread = new Thread(new Task<Void>() {
#Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
#Override
public void run() {
for (int i = 0; i < selectedItem.getChildren().size(); i++) {
TreeItem<Object> current = (TreeItem<Object>) selectedItem.getChildren().get(i);
if (!current.isLeaf()) {
current.setExpanded(true);
}
current = null;
}
selectedItem.setExpanded(true);
System.gc();
}
});
return null;
}
});
thread.setDaemon(true);
thread.start();
}
}
Below is the custom TreeCell class.
public class TargetTreeCell extends TreeCell<Object> {
private TargetTree targetTree;
public TargetTreeCell(TargetTree targetTree) {
super();
this.targetTree = targetTree;
}
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
if (item instanceof Target) {
initTarget(item);
} else if (item instanceof Measure) {
initMeasure(item);
} else if (item instanceof Section) {
initSection(item);
} else if (item instanceof Department) {
initDepartment(item);
} else if (item instanceof String) {
initRoot(item);
}
}
}
///<editor-fold defaultstate="collapsed" desc="Tree Item Initialization">
private void initRoot(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand All");
MenuItem collapseAllMenuItems = new MenuItem("Collapse All");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Root Tree Item.
String root = (String) item;
setText(root);
setContextMenu(contextMenu);
}
private void initDepartment(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand All");
MenuItem collapseAllMenuItems = new MenuItem("Collapse All");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.expandChildren();
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Department Tree Item.
Department department = (Department) item;
setText(department.getName());
setContextMenu(contextMenu);
}
private void initSection(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand All");
MenuItem collapseAllMenuItems = new MenuItem("Collapse All");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.expandChildren();
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Section Tree Item.
Section section = (Section) item;
setText(section.getName());
setContextMenu(contextMenu);
}
private void initMeasure(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand");
MenuItem collapseAllMenuItems = new MenuItem("Collapse");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.expandChildren();
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Section Tree Item.
Measure measure = (Measure) item;
setText(measure.getLastname() + " " + measure.getFirstname());
setContextMenu(contextMenu);
}
private void initTarget(Object item) {
//Init Section Tree Item.
Target target = (Target) item;
setText(target.getText());
}
///</editor-fold>
}
If I have a copy-paste error please forgive me..I don't have problem with compiling. The code is running without errors. My problem is on the methods expandChildren() and collapseChildren() of the first class. In a previous version I didn't used threads and I used recursion to make all the children TreeItems (and their children TreeItems..) to collapse but the memory cost was more.

I found the answer to my problem! I will explain it with an example.
I initialize a TreeView with 100 TreeItems and the result is a tree structure with 3 levels.
On the screen the tree was displaying only 45 of them. To view the others i had to scroll up/down or to expand the collapsed TreeItems. On each case, the method updateItem is called to construct the new TreeItems that will appear to the visible on screen tree and therefore they all was appearing in the screen.
When i collapse an expanded TreeItem then the updateItem method will run. This was the reason of the memory and cpu cost! I had to collapse ~ 200 TreeItems that was all, and their parent expanded.
I solved my problem with a very simple way. Just before i started to collapse everything, i collapsed the parent TreeItem. Thus, i first collapsed the parent and then all the children. When the children was collapsed one by one from the source code (setExpanded(false)), the updateItem method was NOT running because their parent and therefore the children TreeItems was not existed in the screen.
On this way i saved a lot of memory and cpu time that i was spend like a dummy.

I did the same mistake,
happened as i implemented a MenuItem to collapse whole TreeItems (current selection as parent) child branches completely. But the collapse method clears the selection to minus one (-1) and that change wasn't visible because it didn't refreshed the parent item cell afterwards. So it seemed like nothing has changed at first sight because the focus was still visible on the same row.
I guess the skins selector needs to be cleared to do the collapse on child items, or taking over the selection index. so just collapse the parent item at first of which all child items should be folded and reset the selection index afterwards then unfold the parent item again.

Related

JavaFX TreeView ContextMenu for each TreeItem [duplicate]

I want to have a context menu on a TreeView item.
I am expecting that the ActionEvent of the event handler gives me information about which TreeView item is clicked, but I just find that getSource and getTarget return a Menu Item. How can I find out which TreeView Item has been clicked? I can have multiple treevIews in separate Tabs.
FileContextMenu cm = new FileContextMenu(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Open File");
//MenuItem mi = (MenuItem)e.getSource();
EventTarget et = e.getTarget();
//File editorFile = new File(mi.getId());
System.out.println(et);
//mainWindowController.openEditor(editorFile);
}
}, new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Create Project From Template");
}
});
which calls this:
public class FileContextMenu extends ContextMenu
{
public FileContextMenu(EventHandler<ActionEvent> ehOpenFile,
EventHandler<ActionEvent> ehProjectFromTemplate)
{
MenuItem item1 = new MenuItem("Open File");
item1.setOnAction(ehOpenFile);
MenuItem item2 = new MenuItem("Create Project From Template");
item2.setOnAction(ehProjectFromTemplate);
this.getItems().addAll(item1, item2);
}
}
I am attaching the menu here:
private void addFilesTab(FXMLLoader loader, String sRoot, ContextMenu cm) throws IOException
{
AnchorPane fileView = loader.load();
FileViewController fileViewController = loader.getController();
FileShort fsRoot = new FileShort(sRoot);
if(fsRoot.exists()) {
fileViewController.setRootFolder(fsRoot);
fileViewController.setContextMenu(cm);
ObservableList<Tab> tabs = navigationTabPane.getTabs();
tabs.add(new Tab(sRoot));
// Connect the FileView with last tab of the Navigation TabPane.
tabs.get(tabs.size()-1).setContent(fileView);
}
}
which calls this:
public void setContextMenu(ContextMenu cm)
{
fileTreeView.setContextMenu(cm);
}
I now try to use a cellfactory, but I don't understand how to use the p parameter to find a cells value . My code for this is:
this.fileTreeView.setCellFactory(new Callback<TreeView<FileShort>,TreeCell<FileShort>>(){
#Override
public TreeCell<FileShort> call(TreeView<FileShort> p) {
TreeCell<FileShort> cell = new TreeCell<FileShort>();
cell.setContextMenu(cm);
return cell;
}
});
You have to create a different context menu for each cell:
this.fileTreeView.setCellFactory(new Callback<TreeView<FileShort>,TreeCell<FileShort>>(){
#Override
public TreeCell<FileShort> call(TreeView<FileShort> p) {
TreeCell<FileShort> cell = new TreeCell<FileShort>() {
#Override
protected void updateItem(FileShort file, boolean empty) {
super.updateItem(file, empty);
if (empty) {
setText(null);
} else {
// maybe use a more appropriate string for display here
// e.g. if you were using a regular java.io.File you would
// likely want file.getName()
setText(file.toString());
}
}
};
ContextMenu cm = createContextMenu(cell);
cell.setContextMenu(cm);
return cell;
}
});
private ContextMenu createContextMenu(TreeCell<FileShort> cell) {
ContextMenu cm = new ContextMenu();
MenuItem openItem = new MenuItem("Open File");
openItem.setOnAction(event -> {
FileShort file = cell.getItem();
if (file != null) {
// open the file...
}
});
cm.getItems().add(openItem);
// other menu items...
return cm ;
}

How can i get last ListCell in ListView?

I have started making a program in JavaFX where i have ListView with added functionality like editing, adding new items and deleting.I have managed to do most of the work but there is still a little more to do. So far i have added the deleting and editing functionality successfully but i have got a small problem with the adding functionality. I can still add new items to the ListView but i can't make it possible to edit the newly added item, because i need the ListCell the new item represents to start editing it. So my question is how can i get the ListCell of the new item in the ListView.
For this purpose here is my code:
private TextField textField;
ListCell<String> cell = this;
int i = 0;
boolean manually_selected = false;
public LanguageListCell(ListView<String> languages)
{
ContextMenu contextMenu = new ContextMenu();
cell.setEditable(true);
MenuItem editItem = new MenuItem();
editItem.textProperty().bind(Bindings.format("Edit \"%s\"", cell.itemProperty()));
editItem.setOnAction(event -> {
// The LanguageListCell class i want to put here...
cell.startEdit();
});
MenuItem addItem = new MenuItem("Add language");
addItem.setOnAction(new EventHandler<ActionEvent> () {
#Override
public void handle(ActionEvent ev)
{
i++;
String lang = "New Language " + i;
languages.getItems().add(lang);
if(i == 10)
{
addItem.setDisable(true);
}
languages.getSelectionModel().clearSelection();
languages.getSelectionModel().select(languages.getItems().size() - 1);
cell.setItem(languages.getSelectionModel().getSelectedItem());
manually_selected = true;
}
});
MenuItem deleteItem = new MenuItem();
deleteItem.textProperty().bind(Bindings.format("Delete \"%s\"", cell.itemProperty()));
deleteItem.setOnAction(new EventHandler<ActionEvent> () {
#Override
public void handle(ActionEvent ev)
{
if(languages.getSelectionModel().getSelectedItems().size() - 1 > 0)
{
if(i > 0)
{
i = (languages.getItems().size() - languages.getSelectionModel().getSelectedItems().size()) - 1;
}
/*for(String lang: languages.getSelectionModel().getSelectedItems())
{
languages.getItems().remove(lang);
}*/
ArrayList<String> delete_data = new ArrayList<String>(languages.getSelectionModel().getSelectedItems());
languages.getItems().removeAll(delete_data);
}
languages.getItems().remove(cell.getItem());
if(i > 0) i = 0;
}
});
contextMenu.setOnShowing(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
if(languages.getSelectionModel().getSelectedItems().size() - 1 > 0)
{
editItem.setDisable(true);
addItem.setDisable(true);
}
}
});
contextMenu.getItems().addAll(addItem, editItem, deleteItem);
cell.textProperty().bind(cell.itemProperty());
cell.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
cell.setContextMenu(null);
} else {
cell.setContextMenu(contextMenu);
}
});
}

Tree View JavaFX Memory out of Space

I have created javaFX tree with custom Objects (SystemNode).
Tree Items has graphics: check-box and image icon which I have set through updateItems() method.
Whenever I expand or collapse Item in tree ,twice or thrice I get JAVA HEAP MEMORY OUT OF SPACE and whole UI hangs UP.
PS: updateItems() method is invoked every time I expand or collapse tree node
I have tried adding event handlers but they didn't work.
Can anyone give some solutions.
Here is how I set cellFactory :
treeView_technicalAreas.setCellFactory(Util.getTreeCellFactory());
Here is code for cell factory:
public static Callback<TreeView<SystemNode>, TreeCell<SystemNode>> getTreeCellFactory() {
Callback<TreeView<SystemNode>, TreeCell<SystemNode>> callback = new Callback<TreeView<SystemNode>, TreeCell<SystemNode>>() {
#Override
public TreeCell<SystemNode> call(TreeView<SystemNode> p) {
TreeCell<SystemNode> cell = new TreeCell<SystemNode>() {
#Override
protected void updateItem(SystemNode t, boolean isEmpty) {
super.updateItem(t, isEmpty); //To change body of generated methods, choose Tools | Templates.
if (!isEmpty) {
System.out.println("util call back : " + t.getSystem().getName());
setText(t.getSystem().getName());
HBox hBox = new HBox();
CheckBox checkBox = new CheckBox();
checkBox.setSelected(t.getSelected());
checkBox.selectedProperty().bindBidirectional(t.getSelectedProperty());
hBox.setSpacing(SPACING_BETWEEN_ICON_AND_CHECKBOX);
ImageView imageView_icon = null;
if (t.getSystem().getType() == TYPE.BAREA) {
imageView_icon = new ImageView(Constant.Image_AREAS);
} else if (t.getSystem().getType() == TYPE.AREA) {
imageView_icon = new ImageView(Constant.Image_AREAS);
} else if (t.getSystem().getType() == TYPE.DOCUMENT) {
imageView_icon = new ImageView(Constant.Image_DOCUMENTS);
} else if (t.getSystem().getType() == TYPE.NOUN_NAME) {
imageView_icon = new ImageView(Constant.Image_NOUN_NAME);
} else if (t.getSystem().getType() == TYPE.CHANGE) {
imageView_icon = new ImageView(Constant.Image_DCC);
} else if (t.getSystem().getType() == TYPE.TASK) {
imageView_icon = new ImageView(Constant.Image_TASK);
}
hBox.getChildren().addAll(checkBox, imageView_icon);
setGraphic(hBox);
}
}
};
return cell;
}
};
return callback;
}

TableView - Move up and Move down functionality of a cell

I have a situation where I have a TableView. I'm trying to implement a feature that allows a cell to be moved up or down. After moving the cell up or down (with the cell content), I want to change focus to the new location of the cell.
The problem is that it doesn't change to the new location. It for some reason stays in the original selected cell location.
This is the code used to move up, move down and change focus:
I am attempting to move a single selected cell.
public class TableController
{
private ObservableList<SimpleStringProperty> observablePrnPropertyData;
#FXML
private TableView<SimpleStringProperty> table;
#FXML
private TableColumn<SimpleStringProperty, String> data;
#FXML
private void initialize()
{
this.data.setCellValueFactory(cellData -> cellData.getValue());
this.data.setCellFactory(event -> new EditCell(this.observablePrnPropertyData, this.table));
}
public void display(final PrnProperty prnProperty)
{
this.observablePrnPropertyData = PrnPropertyUtil.getObservableDataFromPrnProperty(prnProperty);
this.table.setItems(this.observablePrnPropertyData);
}
private final class EditCell extends TableCell<SimpleStringProperty, String>
{
#Override
public void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (empty)
{
this.setText(null);
this.setGraphic(null);
}
else
{
this.setUpContextMenu();
this.setText(this.getString());
this.setGraphic(null);
}
}
private void setUpContextMenu()
{
// Context menu
ContextMenu contextMenu = new ContextMenu();
// context menu Move up
this.moveUp = new MenuItem("Move up");
this.moveUp.setOnAction(event -> this.moveUp(this.table, this.observablePrnPropertyData));
contextMenu.getItems().add(this.moveUp);
// Context menu for move down
this.moveDown = new MenuItem("Move down");
this.moveDown.setOnAction(event -> this.moveDown(this.table, this.observablePrnPropertyData));
contextMenu.getItems().add(this.moveDown);
// Add context menu
this.setContextMenu(contextMenu);
}
public void moveUp(final TableView<?> table, ObservableList listToManipulate)
{
final int selectedIndex = table.getSelectionModel().getSelectedIndex();
final Object removeItem = listToManipulate.remove(selectedIndex);
final int newIndex = selectedIndex - 1;
listToManipulate.add(newIndex, removeItem);
this.changeTableCellFocus(table, newIndex);
}
public void moveDown(final TableView<?> table, ObservableList listToManipulate)
{
final int selectedIndex = table.getSelectionModel().getSelectedIndex();
final Object remove = listToManipulate.remove(selectedIndex);
final int newIndex = selectedIndex + 1;
listToManipulate.add(newIndex, remove);
this.changeTableCellFocus(table, newIndex);
}
public void changeTableCellFocus(final TableView<?> table, final int focusIndex)
{
table.requestFocus();
table.getSelectionModel().clearAndSelect(focusIndex);
table.getFocusModel().focus(focusIndex);
}
}
}
It would be great if someone can give a working example. I really want to know what i'm doing wrong.
If you just have to focus next and previous line, you can try: table.getFocusModel().focusNext() and .focusPrevious(), like described here: http://docs.oracle.com/javafx/2/api/javafx/scene/control/FocusModel.html
For your case use this code will work fine, it is simple you must first get the selected index, move the item to the next (or previous) row, then select this new row.
void upClicked(){
if(table.getSelectionModel().getSelectedItem() != null) // check if the user really selected a row in the table
{
if(table.getSelectionModel().getSelectedIndex() != 0) // if the row first one so do nothing
{
int index = table.getSelectionModel().getSelectedIndex(); // get the selected row index
SimpleStringProperty x = table.getSelectionModel().getSelectedItem(); // get the selected item
table.getItems().set(index, table.getItems().get(index-1)); // move the selected item up
table.getItems().set(index-1, x); // change the row with the item in above
table.getSelectionModel().select(index-1); // select the new row position
}
}
}
void downClicked(){
if(table.getSelectionModel().getSelectedItem() != null)
{
if(table.getSelectionModel().getSelectedIndex() != table.getItems().size()-1) // if the row is in last so dont do nothing
{
int index = table.getSelectionModel().getSelectedIndex();
SimpleStringProperty x = table.getSelectionModel().getSelectedItem();
table.getItems().set(index, table.getItems().get(index+1));
table.getItems().set(index+1, x);
table.getSelectionModel().select(index+1);
}
}
}

JavaFX CheckBoxTreeItem Selection

I have a javafx checkbox tree. I need to select the checkbox when the tree item is clicked. I have added a listener for the selection property of the tree view. But the listener gets fired only when the tree item is clicked. The above listener is not fired when the checkbox is clicked.
Required: A listener that fires when a tree item or checkbox is clicked in the treeview.
Code:
String memberArray = {"subChild1", "subChild2", "childSub1"}
Group groupRoot = new Group();
Scene scene = new Scene(groupRoot, Color.ALICEBLUE);
HBox hBox = new HBox();
hBox.setMaxWidth(fxPanel.getWidth());
final Label royalLabel = new Label("Select a item");
TreeSet<String> prefixMember = new TreeSet<String>();
String tmpName = null;
LinkedHashSet<CheckBoxTreeItem<String>> treeItems = new LinkedHashSet<CheckBoxTreeItem<String>>();
LinkedHashSet<CheckBoxTreeItem<String>> treeSubItems = new LinkedHashSet<CheckBoxTreeItem<String>>();
for (String item : memberArray) {
if (!item.isEmpty()) {
tmpName = item.substring(0, 3);
prefixMember.add(tmpName);
}
}
// Create and empty TreeView
TreeView<String> duckTree = new TreeView<String>();
// Create TreeItems for the Hierarchy of the TreeView
CheckBoxTreeItem<String> root = new CheckBoxTreeItem<String>("Parent");
CheckBoxTreeItem<String> lm1 = new CheckBoxTreeItem<String>("Child1");
CheckBoxTreeItem<String> lm2 = new CheckBoxTreeItem<String>("Child2");
for (String item : prefixMember) {
CheckBoxTreeItem<String> treeItem = new CheckBoxTreeItem<String>(item.toString());
for (String subItem : memberArray) {
if (!subItem.isEmpty() && subItem.substring(0, 3).equals(item)) {
CheckBoxTreeItem<String> treeSubItem = new CheckBoxTreeItem<String>(
subItem.toString());
treeSubItems.add(treeSubItem);
}
}
treeItems.add(treeItem);
treeItem.getChildren().addAll(treeSubItems);
treeSubItems.clear();
}
root.getChildren().addAll(treeItems);
treeItems.clear();
// Create a TreeView using the root TreeItem
TreeView<String> royalTree = new TreeView<String>(root);
royalTree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
// Set a ChangeListener to handle events that occur with a Treeitem
// is selected
royalTree.getSelectionModel().selectedItemProperty()
.addListener(new ChangeListener<TreeItem<String>>() {
public void changed(
ObservableValue<? extends TreeItem<String>> observableValue,
TreeItem<String> oldItem, TreeItem<String> newItem) {
// Gets fired only on selection of tree item
// Need to get fired on selection of check box too
// Select the respective checkbox on selection of tree item
}
});
hBox.getChildren().add(royalTree);
groupRoot.getChildren().add(hBox);
fxPanel.setScene(scene);
You could just add an EventHandler to your root item in the tree:
rootItem.addEventHandler(CheckBoxTreeItem.checkBoxSelectionChangedEvent(), new EventHandler<TreeModificationEvent<Object>>() {
#Override
public void handle(TreeModificationEvent<Object> event) {
// Your code here.
}
});
i had the same problem and searched looong time. Sadly there is not offical documentation for this from oracle.
The answer is to set the CellFactory and call the getSelectedStateCallback().call(this.getTreeItem());
for your treeItem in the updateItem:
// set cellFactory
royalTree.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> p) {
// return new CheckBoxTreeCell, you also can make a new class with this
return new CheckBoxTreeCell<String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// call the selectedStat Callback for treeitem
ObservableValue<Boolean> selectedState = getSelectedStateCallback().call(this.getTreeItem());
if (selectedState != null) {
// do something here
}
}
}
};
}
});
i have tested this in fx 8, but it should also work in fx 2.2
happy coding,
kalasch
Yes, adding an event handler to the tree item works. Here is some example code (Java 8) with a TreeView with items as CheckBoxTreeItem:
CheckBoxTreeItem<Path> rootItem = new CheckBoxTreeItem<>(rootDirPath);
rootItem.addEventHandler(
CheckBoxTreeItem.<Path>checkBoxSelectionChangedEvent(),
(TreeModificationEvent<Path> e) -> {
CheckBoxTreeItem<Path> item = e.getTreeItem();
if (item.isSelected() || item.isIndeterminate()) {
System.out.println("Some items are checked");
}
else {
System.out.println("Some items are unchecked");
}
});
TreeView<Path> tree = new TreeView<>(rootItem);
tree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Do you require an event for each selection immediately? If not you can create an arraylist of all your checkboxtreeitems and iterate through that to check for selected or not selected when you need it.

Categories