2013-03-19 2 views
2

Netbeans 7.2를 사용하여 JavaFX 2.2 응용 프로그램을 개발 중입니다. TreeView와 함께 일하고 있는데 TreeCell을 확장하여 각 TreeItem에 "Collpase All"기능을 가진 MenuItem이있는 컨텍스트 메뉴를 제공했습니다. TreeView의 최대 깊이 수준은 4입니다. 사용자가 Level 2의 TreeItem을 마우스 오른쪽 버튼으로 클릭하고 "Collapse All"을 클릭하면 MenuItem은 수준 3의 모든 TreeItem을 축소합니다 (setExpanded (false)). 아래에서 내가 사용중인 코드를 볼 수 있습니다. 내 문제는이 작업의 메모리 및 CPU 비용입니다. 레벨 3에 250 개의 TreeItem을 삽입했습니다. 모든 작업을 축소하는 비용은 각 축소마다 ~ 200MB의 메모리였습니다. 클릭 한 번으로 약 2 초를 보냈습니다! 내 개발자 컴퓨터 CPU는 Intel i5 (3.3GHz)이고 8GB의 메모리가 있습니다. 하드웨어 비용이 정상입니까? 아니면 코드에 잘못되었습니다. 나는 그들을 붕괴시키기 위해 잘못된 방법을 사용하고 있습니까?모든 treeitems 메모리 비용 수동으로 확장/축소 javafx 2.2

이 클래스는 TreeView를 관리합니다. 데이터베이스에서 데이터를로드하고, 다시로드하고, 선택된 TreeItem을 알고 선택한 TreeItem을 확장/축소합니다. 다음은

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(); 
} 

}

사용자 정의 TreeCell 클래스입니다.

public class TargetTreeCell extends TreeCell {

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> 

}

내가 복사 - 붙여 넣기 오류가있는 경우 me..i 컴파일에 문제가 없습니다 용서해주십시오. 코드가 오류없이 실행 중입니다. 내 문제는 첫 번째 클래스의 expandChildren() 및 collapseChildren() 메서드에 있습니다. 이전 버전에서는 스레드를 사용하지 않았고 재귀를 사용하여 모든 자식 TreeItems (및 해당 자식 TreeItems ..)을 축소했지만 메모리 비용은 더 많았습니다.

+0

더 나은 도움을 받으려면 SSCCE (http://sscce.org)를 게시하십시오. – gontard

답변

3

내 문제에 대한 답변을 찾았습니다. 나는 그것을 예를 들어 설명 할 것이다. TreeView를 100 개의 TreeItem으로 초기화하고 그 결과는 3 개의 레벨을 가진 트리 구조입니다. 화면에는 트리가 45 개만 표시되었습니다. 다른 사람을 보려면 위 또는 아래로 스크롤하거나 축소 된 TreeItems를 확장해야했습니다. 각각의 경우에 updateItem 메소드가 호출되어 화면 트리에 표시되는 새 TreeItem을 구성하므로 모두 화면에 나타납니다.

확장 된 TreeItem을 축소하면 updateItem 메서드가 실행됩니다. 이것이 메모리와 CPU 비용의 이유였습니다! ~ 200 개의 TreeItems가 모두 무너져 야했고, 부모가 확장되었습니다.

매우 간단한 방법으로 문제를 해결했습니다. 모든 것을 축소하기 직전에 부모 TreeItem을 접었습니다. 그래서, 나는 처음에는 부모를 무너 뜨 렸고 모든 아이들은 무너졌습니다. 자식이 소스 코드 (setExpanded (false))에서 하나씩 축소되면 부모 항목과 자식 TreeItems가 화면에 존재하지 않았기 때문에 updateItem 메서드가 실행되지 않았습니다.

이렇게하면 메모리와 CPU 시간이 많이 절약되어 더미처럼 보냈습니다.

+0

고맙습니다. 오늘 1000 개 항목의 트리보기에서 큰 문제가있었습니다. :) – GOXR3PLUS